网站搜索

typescript - Angular 9 - @ContentChildren 的使用


我有一个ButtonGroupComponent,我需要在其中渲染两种类型的子组件:ButtonActionComponent或ButtonNavigationComponent。

我需要通过 @ContentChildren 来投射这些子组件,但我该怎么办,因为不可能同时传递两个选择器?

@ContentChildren(??)
  public children: QueryList<??>;

所以,我尝试了另一种解决方案:我创建了一个组件,GroupableButtonComponent,该组件被两个组件(ButtonActionComponent 和 ButtonNavigationComponent)扩展。

然后我直接将这个组件传递给 ContentChildren:

@ContentChildren(GroupableButtonComponent)
  public children: QueryList<GroupableButtonComponent>;

但我发现孩子仍然是空的。

我尝试的另一种解决方案是利用依赖注入并创建一个 GroupableButton 类:

export class GroupableButton {
}

在 ButtonActionComponent:

@Component({
      selector: "button-action",
      template: `
        ...
      `,
      providers: [{ provide: GroupableButton, useClass: ButtonActionComponent }],
    })
    export class ButtonActionComponent {
        ...
    }

以及 ButtonNavigationComponent:

@Component({
      selector: "button-navigation",
      template: `
        ...
      `,
      providers: [{ provide: GroupableButton, useClass: ButtonNavigationComponent }],
    })
    export class ButtonNavigationComponent {
        ...
    }

我这样使用它:

@ContentChildren(GroupableButton)
  public children: QueryList<GroupableButton>;

但是因为在我的 ButtonGroupComponent 里面我有:

...

this.children
  .toArray()
  .slice(0, visibleButtons)
  .reverse()
  .forEach((button) => {
    const factory = this.factoryResolver.resolveComponentFactory(
      GroupableButton
    );

    const component = this.visibleButtonsContainer.createComponent(
      factory,
      0,
      null,
      [[button.element.nativeElement]]
    );
    this.clonePropertiesFrom(button, component.instance);
    this.buttons.push(component);
  });

...

这次的问题是我无法将 GroupableButton 作为 entryComponents 放入我的模块中。

答案#1

首先,不要使用你现有的提供者,做这个:

providers: [{ provide: GroupableButton, useExisting: forwardRef(() => ButtonActionComponent) }],

这将确保你获得正确的组件,并且可以根据需要循环使用你的组件。

我不确定这是否解决了你的实例化问题,但与其手动实例化你的组件,你有没有考虑过在组件模板中使用老式的 ng-content 标签?

<!-- put this where ever you want to project your buttons.... -->
<ng-content></ng-content>

答案#2

你把解决方案想得太复杂了。

为什么不直接通过字符串选择器查询这两个组件:

@ContentChildren('templateRef1, templateRef2') allTypesOfButtons: QueryList<ButtonActionComponent | ButtonNavigationComponent>;

我花时间在 Stackblitz 上放了一个例子