我想通过对服务器的服务调用来接收HTML数据(这是肯定的。我不能保持模板在本地),并在内部操纵它们如何显示它(无论是作为一个模式或整个页面)。这个带有角度标记的HTML应该循环到一个组件并协同工作。在大多数情况下,Angular JS中的$compile。
我正在开发Angular 5中的解决方案,应该与AOT编译器兼容。我参考了几个解决方案,并对过时和更新的解决方案感到困惑。请帮帮我。我相信你更新后的答案也会对很多人有所帮助。提前谢谢你!
发布于 2017-12-30 06:00:52
为了动态地呈现超文本标记语言,您需要DomSanitizer。例如,就像这样:
<!-- template -->
<div [innerHTML]="htmlData"></div>
// component
import { Component } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
htmlData: any;
constructor(private sanitizer: DomSanitizer) {}
ngOnInit() {
this.htmlData= this.sanitizer.bypassSecurityTrustHtml('<div style="border: 1px solid red;"><h2>Safe Html</h2><span class="user-content">Server prepared this html block.</span></div>');
}
}现在,这就是它的要点。显然,您还需要一个加载机械师。您可能还希望在此块中包含一些数据-如果是简单的数据,它可以是动态的:
this.htmlData = this.sanitizer.bypassSecurityTrustHtml(`<div>${this.someValue}</div>`);对于更复杂的场景,您可能需要创建一个动态组件。
编辑:是一个动态解析的组件示例。这样,您就可以从服务器发送的html动态创建一个组件。
@Component({
selector: 'my-component',
template: `<h2>Stuff bellow will get dynamically created and injected<h2>
<div #vc></div>`
})
export class TaggedDescComponent {
@ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
private cmpRef: ComponentRef<any>;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>,
private backendService: backendService,
) {}
ngAfterViewInit() {
// Here, get your HTML from backend.
this.backendService.getHTMLFromServer()
.subscribe(rawHTML => this.createComponentFromRaw(rawHTML));
}
// Here we create the component.
private createComponentFromRaw(template: string) {
// Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
// As you see, it has an (existing) angular component `some-component` and it injects it [data]
// Now we create a new component. It has that template, and we can even give it data.
const tmpCmp = Component({ template, styles })(class {
// the class is anonymous. But it's a quite regular angular class. You could add @Inputs,
// @Outputs, inject stuff etc.
data: { some: 'data'};
ngOnInit() { /* do stuff here in the dynamic component */}
});
// Now, also create a dynamic module.
const tmpModule = NgModule({
imports: [RouterModule],
declarations: [tmpCmp],
// providers: [] - e.g. if your dynamic component needs any service, provide it here.
})(class {});
// Now compile this module and component, and inject it into that #vc in your current component template.
this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
this.cmpRef = f.create(this.injector, [], null, this.moduleRef);
this.cmpRef.instance.name = 'my-dynamic-component';
this.vc.insert(this.cmpRef.hostView);
});
}
// Cleanup properly. You can add more cleanup-related stuff here.
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}发布于 2018-09-22 18:11:29
这是一个使用eval的动态模板和动态组件类代码的扩展解决方案。关于不带eval的variaton,见下文。
不使用Stackblitz Example的情况下使用eval。
import { Component, ViewChild, ViewContainerRef, NgModule, Compiler, Injector, NgModuleRef } from '@angular/core';
import {CommonModule} from "@angular/common";
import { RouterModule } from "@angular/router"
@Component({
selector: 'app-root',
template: `<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
</div>
<div #content></div>`
})
export class AppComponent {
title = 'Angular';
@ViewChild("content", { read: ViewContainerRef })
content: ViewContainerRef;
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>, ) {
}
// Here we create the component.
private createComponentFromRaw(klass: string, template: string, styles = null) {
// Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
// As you see, it has an (existing) angular component `some-component` and it injects it [data]
// Now we create a new component. It has that template, and we can even give it data.
var c = null;
eval(`c = ${klass}`);
let tmpCmp = Component({ template, styles })(c);
// Now, also create a dynamic module.
const tmpModule = NgModule({
imports: [CommonModule, RouterModule],
declarations: [tmpCmp],
// providers: [] - e.g. if your dynamic component needs any service, provide it here.
})(class { });
// Now compile this module and component, and inject it into that #vc in your current component template.
this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[factories.componentFactories.length - 1];
var cmpRef = f.create(this.injector, [], undefined, this.moduleRef);
cmpRef.instance.name = 'app-dynamic';
this.content.insert(cmpRef.hostView);
});
}
ngAfterViewInit() {
this.createComponentFromRaw(`class _ {
constructor(){
this.data = {some: 'data'};
}
ngOnInit() { }
ngAfterViewInit(){}
clickMe(){ alert("Hello eval");}
}`, `<button (click)="clickMe()">Click Me</button>`)
}
}这是一个没有动态类代码的小变化。通过类绑定动态模板变量不起作用,而是使用了一个函数:
function A() {
this.data = { some: 'data' };
this.clickMe = () => { alert("Hello tmpCmp2"); }
}
let tmpCmp2 = Component({ template, styles })(new A().constructor);发布于 2019-06-18 18:19:57
查看npm包Ngx-Dynamic-Compiler
这个包允许你使用像*ngIf,*ngFor这样的angular指令,使用字符串插值进行数据绑定,并在运行时创建一个真正的动态组件。已提供AOT支持。
https://stackoverflow.com/questions/48028676
复制相似问题