Способ автоматического обнаружения изменений в динамически загружаемом компоненте в Angular

У меня есть компонент, динамически загруженный в <ng-template>.

Вот пример кода:

HTML:

<ng-template #dynamic></ng-template>

TS:

@ViewChild('dynamic', { read: ViewContainerRef })
dynamic: ViewContainerRef;

constructor(
    private compiler: Compiler,
    private injector: Injector
) {}

async ngAfterViewInit() {
    const exampleModule = await import(PATH_TO_A_MODULE_TO_BE_LOADED).then(m => m.ExampleModule);
    const moduleFactory = await this.compiler.compileModuleAsync(exampleModule);
    const moduleRef = moduleFactory.create(this.injector);
    const componentFactory = moduleRef.instance.resolveComponent();
    const ref = container.createComponent(componentFactory, null, moduleRef.injector);
}

Приведенный выше код будет динамически загружать компонент в ExampleModule.

Проблема в том, что компонент не определяет свои изменения автоматически.

Поэтому мне приходится вызывать this.changeDetectorRef.detectChanges() каждый раз, когда что-то меняется в компоненте.

Я хотел бы знать, есть ли способ позволить компоненту автоматически обнаруживать изменения без использования файла ChangeDetectorRef.


comment
Спасибо @yurzui, значит, нужно использовать changeDetectorRef? есть ли обходной путь для этого?   -  person topmoon    schedule 25.07.2020


Ответы (2)


Содержать ng-шаблон внутри div

<div #dynamic>
  <ng-template></ng-template>
</div>

Затем используйте ngAfterViewInit() внутри, который испускает textContent ViewChild #dynamic

person ランス    schedule 04.12.2020

Вам необходимо зарегистрировать его в ApplicationRef https://angular.io/api/core/ApplicationRef#attachview

Вставьте ApplicationRef в свой сервис и вызовите его метод attachView

@ViewChild('dynamic', { read: ViewContainerRef })
dynamic: ViewContainerRef;

constructor(
    private compiler: Compiler,
    private injector: Injector,
    private appRef: ApplicationRef

) {}

async ngAfterViewInit() {
    const exampleModule = await import(PATH_TO_A_MODULE_TO_BE_LOADED).then(m => m.ExampleModule);
    const moduleFactory = await this.compiler.compileModuleAsync(exampleModule);
    const moduleRef = moduleFactory.create(this.injector);
    const componentFactory = moduleRef.instance.resolveComponent();
    const ref = container.createComponent(componentFactory, null, moduleRef.injector);
    this.appRef.attachView(ref);  // NOTE ref might not be the right type, it needs to be a view Ref and I can't check what type it actually is.  
}
person cjd82187    schedule 25.07.2020
comment
кажется, не работает. ref - это экземпляр компонента. - person topmoon; 25.07.2020
comment
This will throw if the view is already attached to a ViewContainer. - описание по ссылке. Мой компонент добавлен к ViewContainer - person topmoon; 25.07.2020