从 SafeValue 访问@ContentChildren

Accessing @ContentChildren from SafeValue

我有一个简单的组件:

@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>

SelectorComponentngAfterContentInit钩子中只得到3个结果(B、C、D元素)。如果元素 A 是 SafeValue,我该如何访问它?

有什么方法可以跳过要求 SafeValue must use [property]=binding(XSS 保护)?有没有其他方法可以访问此组件(我对访问 DOM 元素不感兴趣,而是获取组件引用)。

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

您可以命令式执行

constructor(private elRef:ElementRef) {}

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

或者像

中解释的那样加载动态平台来编译组件 atr untime

感谢@Günter Zöchbauer 和 he has posted in one of the comments and the answer 我找到了解决方案:

我决定使用 ngComponentOutlet 正如文档所说:

NgComponentOutlet provides a declarative approach for dynamic component creation

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

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 编译后,当 运行:

时出现错误

ERROR Error: Runtime compiler is not loaded

在评论之一的原始问题下,@Günter Zöchbauer 发布了 link 到 feature request 可以解决该问题。现在,如果您想使用这种方法,请不要使用 AoT 编译。