lazalu68
@lazalu68
Salmon

Как передать ссылку на объект в качестве compileContext?

Нашел в интернетах код директивы для динамического создания компонентов, в ней используются Compiler:compileModuleAndAllComponentsAsync, ViewContainerRef:createComponent и прочие страшные слова:

compile.directive.ts

import {
    Compiler, NgModule, Component, Input, ComponentRef, Directive,
    ModuleWithComponentFactories, OnChanges, Type,
    ViewContainerRef
} from '@angular/core';
import { CommonModule } from '@angular/common';

@Directive({
    selector: '[compile]'
})
export class CompileDirective implements OnChanges {
    @Input() compile: string;
    @Input() compileContext: any;

    compRef: ComponentRef<any>;

    constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}

    ngOnChanges() {
        if(!this.compile) {
            if(this.compRef) {
                this.updateProperties();
                return;
            }
            throw Error('You forgot to provide template');
        }

        this.vcRef.clear();
        this.compRef = null;

        const component = this.createDynamicComponent(this.compile);
        const module = this.createDynamicModule(component);
        this.compiler.compileModuleAndAllComponentsAsync(module)
            .then((moduleWithFactories: ModuleWithComponentFactories<any>) => {
                let compFactory = moduleWithFactories.componentFactories.find(x => x.componentType === component);

                this.compRef = this.vcRef.createComponent(compFactory);
                this.updateProperties();
            })
            .catch(error => {
                console.log(error);
            });
    }

    updateProperties() {
        for(var prop in this.compileContext) {
            this.compRef.instance[prop] = this.compileContext[prop];
        }
    }

    private createDynamicComponent (template:string) {
        @Component({
            selector: 'custom-dynamic-component',
            template: template,
        })
        class CustomDynamicComponent {}
        return CustomDynamicComponent;
    }

    private createDynamicModule (component: Type<any>) {
        @NgModule({
            // You might need other modules, providers, etc...
            // Note that whatever components you want to be able
            // to render dynamically must be known to this module
            imports: [CommonModule],
            declarations: [component]
        })
        class DynamicModule {}
        return DynamicModule;
    }
}



Используется она как-то так:
// Шаблон компонента
<ng-container *compile="template; context: { some_key: true }"></ng-container>

// Объявление свойства template в текущем компоненте
template = `
  <div *ngIf="some_key">This shit finally works, nice</div>
`;


При выполнении этого чуда в текущем компоненте будет успешно отрендерен <div>This shit finally works, nice</div>.

Основной вопрос: как передать объект чтобы он использовался в качестве compileContext? Ну или чтобы объект был передан как свойство compileContext

И было бы вообще прекрасно если бы была прояснена парочка непонятных для меня моментов:
1. Почему эта директива структурная?
2. Как вообще мапится context на compileContext? Какой механизм обрабатывает строку "template; context: { some_key: true }"?

Заранее спасибо!

Небольшой апдейт: речь не об AOT, а именно о JIT.
  • Вопрос задан
  • 165 просмотров
Решения вопроса 1
Xuxicheta
@Xuxicheta Куратор тега Angular
инженер
1. Так короче. Структурная директива это сахар.
2. Потому что это
<ng-container *compile="template; context: { some_key: true }"></ng-container>

разворачивается в это
<ng-template [compile]="template" [compileContext]="{ some_key: true }">
  <ng-container></ng-container>
</ng-template>


Основной вопрос: как передать объект чтобы он использовался в качестве compileContext? Ну или чтобы объект был передан как свойство compileContext

Передавайте прямо
<ng-container *compile="template; context: myObject"></ng-container>


Небольшой апдейт: Есть подозрение что при AOT компиляции эта директива работать не будет, потому что нет компайлера. Что делает ее полностью бесполезной.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
mazhekin
@mazhekin
Frontend, Backend Web Developer
Angular HTML compiler
Вот компонент которому можно передать динамический темплейт в строке и объект с данными, В проде тоже работает, там в главном модуле нужно один раз прописать модуль для jit
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы