从SafeValue访问@ContentChildren

时间:2017-12-13 08:55:29

标签: angular angular5

我有一个简单的组件:

@Component({
  selector: '[group_id]'
})
export class ItemComponent {}

我还有一个组件,我尝试将所有传递给此组件的子ItemComponent作为内容。

@Component({
    selector    : 'selector',
    template    : '<ng-content></ng-content>',
})
export class SelectorComponent implements AfterContentInit {
    @ContentChildren(ItemComponent) items;

    ngAfterContentInit() {
        console.log (this.items);
    }
}

现在我在应用程序的某个地方使用我的SelectorComponent

<selector>
    <div [innerHTML]="'<p group_id>A</p>' | safeHtml"></div>

    <p group_id>B</p>
    <p group_id>C</p>
    <p group_id>D</p>
</selector>

ngAfterContentInit的{​​{1}}钩子中只获得3个结果(B,C,D元素)。如果元素A是SelectorComponent,我如何访问它?

是否可以跳过要求SafeValue(XSS保护)?是否有其他方法来访问此组件(我不想访问DOM元素,但获取组件引用)。

2 个答案:

答案 0 :(得分:1)

Angular不知道使用[innerHTML]或在运行时动态添加的其他HTML添加的内容。 Angular在构建应用程序时,在部署之前编译模板,并忽略在运行时添加的所有HTML。

你可以强制执行

constructor(private elRef:ElementRef) {}

ngAfterContentInit() {
  this.elRef.nativeElement.querySelector(...)
}

或加载动态平台以编译组件atr untime,如How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

中所述

答案 1 :(得分:1)

感谢@GünterZöchbauer和link他发表了一条评论和答案here我找到了解决方案:

我决定使用文档所说的ngComponentOutlet

  

NgComponentOutlet为动态组件创建提供了一种声明方法

首先我做了一个动态组件:

import {Component, OnChanges, OnInit, Input, NgModule,NgModuleFactory,Compiler, SimpleChanges} from '@angular/core';
import { SharedModule } from './shared.module';

@Component({
    selector: 'dynamic',
    template: `<ng-container *ngComponentOutlet="dynamicComponent;ngModuleFactory: dynamicModule;"></ng-container>`
})
export class DynamicComponent {

    dynamicComponent: any;
    dynamicModule   : NgModuleFactory<any>;

    @Input('html') html: string;

    constructor(private compiler: Compiler) {}

    ngOnChanges(changes: SimpleChanges) {
        if (changes['html'] && !changes['html'].isFirstChange()) {
            this.dynamicComponent = this.createNewComponent(this.html);
            this.dynamicModule    = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));
        }
    }

    ngOnInit() {
        this.dynamicComponent = this.createNewComponent(this.html);
        this.dynamicModule    = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));
    }

    protected createComponentModule(componentType: any) {
        @NgModule({
            imports     : [SharedModule],
            declarations: [
                componentType
            ],
            entryComponents: [ componentType ]
        })
        class RuntimeComponentModule {
        }
        // a module for just this Type
        return RuntimeComponentModule;
    }

    protected createNewComponent(template: string) {

        @Component({
            selector: 'dynamic-component',
            template: template ? template: '<div></div>'
        })
        class MyDynamicComponent {}

        return MyDynamicComponent;
    }
}

然后我将动态组件导入我的模块:

import { DynamicComponent } from './dynamic-item/dynamic-item';

@NgModule({
    declarations: [
        ...
        DynamicComponent,
    ],
    exports: [
        ...
        DynamicComponent,
    ]
})
export class ComponentsModule { }

不,我可以将动态组件用于任何动态加载的html模板:

<dynamic [html]="dynamicHtml"></dynamic>

其中dynamicHtml可以包含任何现有组件/指令/等的任何html:

dynamicHtml: string = "<p group_id>A</p>";

值得注意的是,这种方法需要JIT编译器,因此在开发过程中一切正常,但在使用AoT进行编译后,运行时出错:

  

错误错误:未加载运行时编译器

根据其中一条评论中的原始问题,@GünterZöchbauer发布了feature request的链接,可以解决该问题。目前,如果您想使用此方法,请不要使用AoT编译。