Angular 2 Динамически вставить компонент в определенный узел DOM без использования ViewContainerRef
У меня есть вопрос, касающийся создания динамических компонентов в Angular 2 RC5.
Итак, давайте предположим, что у нас есть два простых угловых компонента:
@Component({
template: `
<div id="container">
<h1>My Component</h1>
</div>
`,
selector: 'my-app'
})
export class AppComponent { }
@Component({
template: '<p>{{text}}</p>',
selector: 'simple-cmp'
})
export class SimpleComponent { public text='Hello World!' }
Затем некоторый внешний неугловой кусок кода модифицирует DOM:
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
Вот несколько предположительных деревьев после манипуляций:
<div id="container">
<h1>My Component</h1>
<div id="placeholder"></div>
</div>
Так что я пытаюсь просто динамически добавить экземпляр SimpleComoponent в #placeholder div. Как мне достичь этого результата?
Я пытался использовать ComponentFactory.createComponent(injector, [], newNode), хотя он добавил компонент, но ни перехватчики жизненного цикла, ни привязка не работали вообще.
Я считаю, что есть какой-то способ реализовать это с помощью ViewContainerRef, но как я могу связать его с динамически созданным узлом?
Вот результат, который я ожидаю
<div id="container">
<h1>My Component</h1>
<div id="placeholder">
<simple-cmp>Hello world!</simple-cmp>
</div>
</div>
Спасибо!
2 ответа
При создании компонента вы можете передать узел DOM, который будет действовать как элемент хоста созданного компонента:
create (инжектор: инжектор, projectableNodes?: any [] [], rootSelectorOrNode?: string | any, ngModule?: NgModuleRef): ComponentRef
Но так как этот компонент не является дочерним по отношению к любому другому компоненту, вы должны вручную присоединить его к ApplicationRef, чтобы вы могли обнаружить изменения.
Итак, вот что вам нужно сделать:
1) Создайте компонент, определяющий корневой узел, под которым он должен быть добавлен.
2) Присоедините представление к ApplicationRef, чтобы получить обнаружение изменений. У тебя еще не будет Input
а также ngOnChanges
операции, но обновление DOM будет работать нормально.
@Component({
template: `
<div id="container">
<h1>My Component</h1>
</div>
`,
selector: 'my-app'
})
export class AppComponent {
constructor(private resolver: ComponentFactoryResolver,
private injector: Injector,
private app: ApplicationRef) {
}
addDynamicComponent() {
let factory = this.resolver.resolveComponentFactory(SimpleComponent);
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
const ref = factory.create(this.injector, [], newNode);
this.app.attachView(ref.hostView);
}
}
Вы никогда не должны изменять DOM вне Angular, потому что это приведет к непредсказуемому поведению. Даже если вы добавляете <simple-cmp>
Элемент вручную, это ничего не значит, потому что он не обрабатывается Angular. Все изменения в DOM внутри приложения Angular должны проходить через методы Angular.
Динамически создайте новый компонент:
@Component({
selector: 'my-component',
template: '<div #element></div>',
})
export class MyComponent {
@ViewChild('element', {read: ViewContainerRef}) private anchor: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
whatever() {
let factory = this.resolver.resolveComponentFactory(ChildComponent);
this.anchor.createComponent(factory);
}
}