【问题标题】:Create dynamic components with different location in logical component tree在逻辑组件树中创建具有不同位置的动态组件
【发布时间】:2020-02-29 08:46:57
【问题描述】:

我希望构建一个组件,它使用 Angular 的 componentFactoryResolvercomponentFactory 将组件动态注入 DOM,但使用传入的 viewContainerRef 来确定可注入的内容。

@Component({
  selector: 'my-component-loader',
  template: ``
})
export class MyComponentLoader implements OnInit  {

  constructor(private viewContainerRef: ViewContainerRef,
              private componentFactoryResolver: ComponentFactoryResolver,
              private componentLoaderService: ComponentLoaderService) {
  }

  ngOnInit() {
      this.componentLoaderService.loadComponent.pipe(
        tap((component, componentViewContainerRef) => this.loadComponent(component, componentViewContainerRef))
      ).subscribe();
  }

  loadComponent(component, callerViewContainerRef) {
    this.viewContainerRef.clear();

    const factory = this.componentFactoryResolver.resolveComponentFactory(component);
    this.viewContainerRef.createComponent(factory);
  }
}

如何在my-component-loader 位置加载组件,逻辑位置来自callerViewContainerRef,以便创建的组件具有可用于callerViewContainerRef 的DI 树。

简而言之,这在方式上类似于 Material 的 MatDialog。

https://github.com/angular/components/blob/master/src/material/dialog/dialog-config.ts

有没有更简单的方法来处理而不复制 Angular CDK 门户逻辑?

** 编辑 **

这就像传入 callerViewContainerRef 的注入器一样简单吗?

this.viewContainerRef.createComponent(factory, 0 , callerViewContainerRef.injector);

【问题讨论】:

    标签: angular


    【解决方案1】:

    就这么简单,就是传入 callerViewContainerRef 的注入器吗?

    我认为这是正确的。这是我的一个单独的例子,它让我有了更好的理解。

    app.tokens.ts

    export const FooToken = new InjectionToken('foo');
    

    app.module.ts

    @NgModule({
     /* ... */
     providers: [
      {
       provide: FooToken,
       useValue: { message: 'default foo value' }
      }
     ]
    })
    export class AppModule { }
    

    app.component.ts

    @Component({
      selector: 'my-app',
      template: `
        <ng-container #vcr></ng-container>
      `,
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
      @ViewChild('vcr', { static: true, read: ViewContainerRef })
      vcr: ViewContainerRef;
    
      ngAfterViewInit () {
        const compFactory = this.cfr.resolveComponentFactory(FooComp);
    
        const inj = Injector.create({
          providers: [
            {
              provide: FooToken,
              useValue: { message: 'this is just a foo message from a dynamic injector!' }
            }
          ]
        })
    
        this.vcr.createComponent(compFactory, 0, inj); 
      }
    }
    

    foo.component.ts

    @Component({
      selector: 'foo',
      template: `Foo!!`
    })
    export class FooComp {
      constructor (@Inject(FooToken) private fooToken) {
        console.log('[FOO]', this.fooToken)
      }
    }
    

    如果您按原样运行代码,您应该会在 Foo 的构造函数中看到 { message: 'this is just a foo message from a dynamic injector!' }

    但是,如果您创建组件时没有指定自定义注入器

    this.vcr.createComponent(compFactory);
    

    你应该看到这个:{ message: 'default foo value' }

    你可以在我的playground找到上述想法。

    【讨论】:

      猜你喜欢
      • 2019-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 1970-01-01
      • 2021-09-28
      • 2012-05-20
      相关资源
      最近更新 更多