首页 > 解决方案 > Angular 9 - use of @ContentChildren

问题描述

I have a ButtonGroupComponent in which i need to render two types of children: ButtonActionComponent or ButtonNavigationComponent.

I need to project these children via @ContentChildren, but what can i do, since it is not possible to pass both selectors?

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

So, I tried another solution: I created a component, GroupableButtonComponent, which is extended by the two (ButtonActionComponent and ButtonNavigationComponent).

And then I passed directly this component to ContentChildren:

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

But I found that children remains empty.

Another solution I tried was to exploit dependency injection and create a GroupableButton class:

export class GroupableButton {
}

where ButtonActionComponent:

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

and ButtonNavigationComponent:

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

I used it this way:

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

but since inside my ButtonGroupComponent I have:

...

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);
  });

...

this time the problem is that I can't pass GroupableButton as entryComponents inside my module.

标签: angulartypescript

解决方案


first, instead of the providers you have, do this:

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

this will ensure you're getting the correct component and can loop your components as you see fit.

I'm not sure this solves your instantiation issue, but instead of manually instantiating your components, have you considered the good old ng-content tag in your component template?

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

推荐阅读