【问题标题】:Angular - change detection in dynamically loaded module/component without using `ChangeDetectorRef`Angular - 动态加载的模块/组件中的更改检测而不使用`ChangeDetectorRef`
【发布时间】:2020-11-14 23:24:31
【问题描述】:

我用编译器的compileModuleAsync 编译了一个 Angular 模块(以动态加载模块),并希望将模块的一个组件插入到视图中。

我尝试将组件插入ViewContainer,但组件不会自动检测更改。每次更新组件的属性时,我都应该调用changeDetectorRef.detectChanges

有什么方法可以在不使用changeDetectorRef 的情况下实现这一点?

Angular 版本是10.0.4

我加载组件的示例代码:


我加载另一个组件的组件:

<ng-template #dynamic></ng-template>
@ViewChild('dynamic', { read: ViewContainerRef })
dynamic: ViewContainerRef;

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

async ngAfterViewInit() {
    // Load a module dynamically
    const exampleModule = await import('../example/example.module').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);
}

示例模块:

@NgModule({
    declarations: [
        ExampleComponent
    ],
    imports: [...]
})
export class ExampleModule {
    constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

    public resolveComponent(): ComponentFactory<ExampleComponent> {
        return this.componentFactoryResolver.resolveComponentFactory(ExampleComponent);
    }
}

调用detectChanges的示例案例:

示例组件

<button (click)="toggle()">Show/Hide</button>
<span *ngIf="show">Show</span>
public toggle() {
  this.show = !this.show;
  this.cdr.detectChanges(); // <- I want to not use this.
}

【问题讨论】:

  • 如何将输入传递给组件?你在哪里调用 changeDetectorRef?
  • 嗨@David,传递输入很好,我更新了问题。只想让它自动检测变化。
  • 这似乎工作正常:stackblitz.com/edit/…
  • 哦,我可以看到它有效。但它在我这边不起作用
  • 你能用你的真实代码试试 stackblitz 吗?

标签: angular angular2-changedetection angular-dynamic-components change-detector-ref


【解决方案1】:

我使用这个服务来创建组件一组输入:

@Directive({
  selector: '[formField]'
})
export class FormFieldDirective implements Field, OnChanges, OnInit, AfterViewInit {
  @Input() config: FieldConfig;
  @Input() lang: string;
  @Input() group: FormGroup;

  @Input('class') classList: string = 'col-12';

  component: ComponentRef<Field>;

  constructor(
    private resolver: ComponentFactoryResolver,
    private container: ViewContainerRef,
    private renderer: Renderer2
  ) { }

  ngOnChanges() {
    if (this.component) {
      this.component.instance.config = this.config;
      this.component.instance.group = this.group;
    }
  }

  ngOnInit() {
    if (!components[this.config.type]) {
      const supportedTypes = Object.keys(components).join(', ');
      throw new Error(
        `Trying to use an unsupported type (${this.config.type}).
        Supported types: ${supportedTypes}`
      );
    }
    const component = this.resolver.resolveComponentFactory<Field>(components[this.config.type]);
    this.component = this.container.createComponent(component);
    this.renderer.addClass(this.component.location.nativeElement, this.config.widthClass ? this.config.widthClass : 'col-12');
    this.component.instance.config = this.config;
    this.component.instance.group = this.group;
    this.component.instance.lang = this.lang;
    if (this.config.type === ModelType.group) {
      this.component.instance.innerForm = this.group.get(this.config.name) as FormGroup;
    }

  }

  ngAfterViewInit() {
    this.config.label += 'cica';
  }
}

用法:

<div [ngClass]="formClass" [formGroup]="form">
    <ng-container *ngFor="let field of config;" formField [config]="field" [lang]="lang" [group]="form"> </ng-container>
    <ng-content></ng-content>
</div>

【讨论】:

  • 你的动态组件会自动检测变化吗?
  • 我没有尝试过,因为我使用store和forn-control来传递数据,所以我的输入无法更改。但是如果 wrappercomponent 的输入发生了变化,如果你将它传递给实例,它应该反映到它,或者如果没有其他选项应该重新渲染。我试试看。
  • 是的,它将在 init 上工作。但在组件内部,我做了一些操作,值将被更新。在这种情况下,组件视图不会更新,因为它不监听更改。我每次都必须手动调用 changeDetectorRef。
  • 我改变了我的例子。如果我更改输入,其值反映到动态组件(ngAfterViewInit)
  • @yash,你不能在 OnChange 钩子中运行这些操作吗?
猜你喜欢
  • 2017-08-27
  • 2018-11-03
  • 2018-01-06
  • 1970-01-01
  • 2022-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-07
相关资源
最近更新 更多