Динамическое отображение элементов, содержащих HTML с функциями (щелчком) Angular 2
У меня есть рекурсивная древовидная структура, содержащая узлы, каждая из которых имеет свойство "htmlStringContent". Когда я показываю дерево с помощью вложенных компонентов node и пытаюсь представить содержимое html, которое я использую:
<div [innerHtml]="node.htmlStringContent"></div>
HTML отображается правильно, но для следующих элементов:
<a (click)="function()">click me</a>
Функции (нажмите) не работают. Я знаю, что ранее было опубликовано , но с большим количеством обновлений angular недавно вышло, что я не могу найти какие-либо решения. Этот ответ заставляет меня думать, что я должен использовать директиву ngComponentOutlet, но я не уверен, как..
Как я могу получить angular для привязки этой функции щелчка?
Изменить: мне сказали использовать ComponentFactoryResolver, но не вижу, как я могу использовать это, чтобы правильно отображать html. Может ли кто-нибудь помочь?
Edit2: я обрабатываю "htmlStringContent" через санирующую трубу перед ее отображением на [ innerHtml]
transform(v: string) : SafeHtml {
return this._sanitizer.bypassSecurityTrustHtml(v);
}
Edit3: В основном этот вопрос задается вопросом, возможно ли отображать HTML из свойства объекта в angular 2/ionic 2, сохраняя при этом функциональность (щелчок). Я также открыт для обходных ответов.
Ответы
Ответ 1
CFR DEMO: https://plnkr.co/edit/jKEaDz1JVFoAw0YfOXEU?p=preview
@Component({
selector: 'my-app',
template: `
<button (click)="addComponents()">Add HTML (dynamically using CRF)</button>
<h1>Angular2 AppComponent</h1>
<hr>
<div>
<h5>dynamic html goes here</h5>
<div class="container">
<template #subContainer1></template>
</div>
</div>
`,
})
export class App {
name:string;
@ViewChild('subContainer1', {read: ViewContainerRef}) subContainer1: ViewContainerRef;
constructor(
private compFactoryResolver: ComponentFactoryResolver
) {
this.name = 'Angular2'
}
addComponents() {
let compFactory: ComponentFactory;
compFactory = this.compFactoryResolver.resolveComponentFactory(Part1Component);
this.subContainer1.createComponent(compFactory);
}
}
Ответ 2
Если я правильно понимаю, вам нужно использовать динамические шаблоны и скомпилировать их во время выполнения. Если это так, вам нужно использовать компилятор angular:
@Component({
selector: 'my-app',
template: `
<h1>Angular 2 Dynamic Component</h1>
<template #container></template>
`
})
export class AppComponent implements AfterContentInit, OnDestroy {
private dynamicComponentRefs: ComponentRef[] = [];
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver,
private compiler: Compiler) {}
ngAfterContentInit() {
let html = `
<div>Always Visible</div>
<div [hidden]="clause1">Hidden because of clause1 = true</div>
<div [hidden]="clause2">Visible because of clause2 = false</div>
<button type="button" (click)="buttonClicked()">Click me!</button>
<div *ngIf="clicked">You clicked the button!</div>
`;
this.compiler.compileModuleAndAllComponentsAsync(createDynamicComponent(html))
.then((mwcf: ModuleWithComponentFactories) => {
let factory: ComponentFactory = mwcf.componentFactories.find(cf =>
cf.componentType.name === 'DynamicComponent');
this.dynamicComponentRefs
.push(this.container.createComponent(factory));
});
}
ngOnDestroy() {
/* Make sure you destroy all dynamically created components to avoid leaks */
this.dynamicComponentRefs.forEach(dcr => {
dcr.destroy();
});
}
}
export function createDynamicComponent(html: string): Type<NgModule> {
@Component({
template: html,
})
class DynamicComponent {
private clause1: boolean = true;
private clause2: boolean = false;
private clicked = false;
buttonClicked() {
this.clicked = true;
}
}
@NgModule({
imports: [CommonModule],
declarations: [DynamicComponent],
})
class DynamicComponentModule {}
return DynamicComponentModule;
}
В принципе вам необходимо динамически создавать компонент и модуль, который объявляет его (например, через функцию), и передавать ему шаблон в качестве аргумента. Затем вы можете вызвать compileModuleAndAllComponentsAsync()
на модуле и получить компонент factory, который вам нужен. Затем это вопрос рендеринга его в DOM с помощью метода ViewContainerRef.createComponent()
.
Здесь работает plunker: динамический компонент шаблона
Имейте в виду, что на данный момент - этот подход может использоваться только с компиляцией JIT. В компиляции AOT компилятор angular недоступен, и попытка его использования будет вызывать ошибку.