Подтвердить что ты не робот

Angular2: программно создавать дочерние компоненты

Вопрос

Как создать дочерние компоненты внутри родительского компонента и затем отобразить их в представлении с помощью Angular2? Как убедиться, что инъекционные инъекции правильно введены в дочерние компоненты?

Пример

import {Component, View, bootstrap} from 'angular2/angular2';
import {ChildComponent} from './ChildComponent';

@Component({
    selector: 'parent'
})
@View({
  template: `
    <div>
      <h1>the children:</h1>
      <!-- ??? three child views shall be inserted here ??? -->
    </div>`,
  directives: [ChildComponent]
})
class ParentComponent {

        children: ChildComponent[];

        constructor() {
            // when creating the children, their constructors
            // shall still be called with the injectables.
            // E.g. constructor(childName:string, additionalInjectable:SomeInjectable)
            children.push(new ChildComponent("Child A"));
            children.push(new ChildComponent("Child B"));
            children.push(new ChildComponent("Child C"));
            // How to create the components correctly?
        }
}
bootstrap(ParentComponent);

Изменить

Я нашел DynamicComponentLoader в предпросмотре API docs. Но я получаю следующую ошибку, следуя примеру: Отсутствует директива динамического компонента в элементе 0

4b9b3361

Ответ 1

Это вообще не тот подход, который я бы принял. Вместо этого я буду полагаться на привязку данных к массиву, который будет отображать больше дочерних компонентов, поскольку объекты добавляются в массив подстановки. По существу дочерние компоненты, завернутые в ng-for

У меня есть пример, похожий на то, что он отображает динамический список дочерних элементов. Не 100% то же самое, но похоже, что концепция все та же:

http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0

Ответ 2

Предупреждение: DynamicComponentLoader устарел в RC.4

В Angular 2.0, loadIntoLocation метод DynamicComponentLoader служит для создания отношений родитель-потомок. Используя этот подход, вы можете динамически создавать отношения между двумя компонентами.

Вот пример кода, в котором бумага является моим родителем, а бюллетень - моим дочерним компонентом.

paper.component.ts

import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';

@Component({
    selector: 'paper',
    templateUrl: 'app/views/paper.html'

    }
})
export class PaperComponent {
    constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {

    }

    ngOnInit(){
        this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');

    }
}

bulletin.component.ts

import {Component} from 'angular2/core';

@Component({
    selector: 'bulletin',
    template: '<div>Hi!</div>'
    }
})
export class BulletinComponent {}

paper.html

<div>
    <div #child></div>
</div>

В этом ответе упоминается несколько вещей, о которых вам нужно позаботиться

Ответ 3

Вы должны использовать ComponentFactoryResolver и ViewElementRef для добавления компонента во время выполнения. Посмотрите ниже код.

let factory = this.componentFactoryResolver.resolveComponentFactory(SpreadSheetComponent);
let res = this.viewContainerRef.createComponent(factory);

Поместите вышеуказанный код в свою функцию ngOnInit и замените "SpreadSheetComponent" на ваше имя компонента.

Надеюсь, что это сработает.

Ответ 4

Программно добавить компоненты в DOM в Angular 2/4 app

Нам нужно использовать метод жизненного цикла ngAfterContentInit() из AfterContentInit. Он вызывается после того, как содержимое директивы полностью инициализировано.

В parent-component.html добавьте a div следующим образом:

<div #container> </div>

Файл parent-component.ts выглядит следующим образом:



class ParentComponent implements AfterContentInit {

  @ViewChild("container", { read: ViewContainerRef }) divContainer

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterContentInit() {
    let childComponentFactory = this.componentFactoryResolver.resolveComponentFactory(childComponent);
    this.divContainer.createComponent(childComponentFactory);
    let childComponentRef = this.divContainer.createComponent(childComponentFactory);
    childComponentRef.instance.someInputValue = "Assigned value";

  }
}

Внутри src\app\app.module.ts добавьте следующую запись в параметры метода @NgModule():


  entryComponents:[
    childComponent
  ],

Обратите внимание, что мы не обращаемся к div#container с помощью подхода @ViewChild("container") divContainer. Нам нужна эта ссылка вместо nativeElement. Мы получим доступ к нему как ViewContainerRef:

@ViewChild("container", {read: ViewContainerRef}) divContainer

ViewContainerRef имеет метод под названием createComponent(), который требует передачи компонента factory в качестве параметра. Для этого нам нужно ввести a ComponentFactoryResolver. Он имеет метод, который в основном загружает компонент.

Ответ 5

Правильный подход зависит от ситуации, которую вы пытаетесь решить.

Если число детей неизвестно, то NgFor - правильный подход. Если он исправлен, как вы упомянули, 3 ребенка, вы можете использовать DynamicComponentLoader для их загрузки вручную. Преимущества ручной загрузки - лучший контроль над элементами и ссылка на них внутри родителя (что также можно получить с помощью шаблонов...)

Если вам нужно заполнить данные детьми, это также можно сделать с помощью инъекции, родитель вводит объект данных, заполняющий детей на месте...

Опять же, много вариантов. Я использовал "DynamicComponentLoader" в моем модальном примере, https://github.com/shlomiassaf/angular2-modal