Use Base Component Type to Query Children in Angular

use base component to query children

Sometimes we might require to use Base Component type to Query Children in a component.

Let us consider a scenario where we have multiple components that extend the same base component type, and use them in a ListView.

BaseItemViewComponent (Base component)

@Component({
  ...
})
export class BaseItemViewComponent { ... }

ItemViewComponent

@Component({
  selector: 'app-item-view'
})
export class ItemViewComponent extends BaseItemViewComponent { ... }

EnhancedItemViewComponent

@Component({
  selector: 'app-enhanced-item-view'
})
export class EnhancedItemViewComponent extends BaseItemViewComponent { ... }

ListViewComponent

<div id="listView>
  <ng-container *ngFor="let item of list">
    <app-item-view *ngIf="item.isSimpleView; else enhancedView"></app-item-view>
    <ng-template #enhancedView>
      <app-enhanced-item-view></app-enhanced-item-view>
    </ng-template>
  </ng-container>
</div>

Now if we want to Query all the ItemView components, including the enhanced ones, there is no direct approach to do that. For accessing all ItemViewComponent’s we can use the following.

@ViewChildren(ItemViewComponent) itemViewList: QueryList<ItemViewComponent>;

We can use ViewChildren to access a component of the same type, but when accessing a heterogenous list it will fail.

Even if we use the BaseItemViewComponent to query, it will not still not return the result.

@ViewChildren(BaseItemViewComponent) itemViewList: QueryList<BaseItemViewComponent>;

This happens because DI doesn’t understand inheritance. But we can achieve this if we publish the inheriting component with a different token. For example:

@Component({
  selector: 'app-item-view',
  providers: [provide(BaseItemViewComponent, useExisting: ItemViewComponent)]
})
export class ItemViewComponent extends BaseItemViewComponent { ... }
@Component({
  selector: 'app-item-view',
  providers: [provide(BaseItemViewComponent, useExisting: EnhancedItemViewComponent)]
})
export class ItemViewComponent extends BaseItemViewComponent { ... }

Now if we query for the BaseItemViewComponent in the ListViewComponent, we will get access to all components in the view which are BaseItemViewComponent. This will also include any component which extends BaseItemViewComponent, that includes ItemViewComponent and EnhancedItemViewComponent.

@ViewChildren(BaseItemViewComponent) itemViewList: QueryList<BaseItemViewComponent>;

To read more tricks on Angular, follow this link.

Leave a Reply