在逻辑组件树中创建具有不同位置的动态组件

时间:2019-11-04 02:47:02

标签: angular

我希望构建一个组件,该组件使用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);

1 个答案:

答案 0 :(得分: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中找到上述想法。