When attempting to view the content, you may encounter difficulties if the mat-tab
components are not direct children of the mat-tab-group
component. In this case, the tabs may not be recognized. To address this issue, a different approach is required. The recommended method involves extracting the content from custom components and then organizing it within a wrapper component. One effective strategy is to extract the content as templates, which closely aligns with your current setup. Begin by focusing on the lower-level components before progressing upwards.
The existing app-item-content
component can remain unchanged. However, adjustments are needed for the app-item-header
. Similar to tab elements, the mat-tab-label
directive must be directly applied within the mat-tab-group
, prompting its removal from the template.
<ng-template>
{{title}}
</ng-template>
A significant modification involves exposing the ng-template
within the component as a property in the code through the use of the ViewChild decorator. This allows external access to the template within the component.
@Component({
selector: 'app-item-header',
templateUrl: './item-header.component.html',
styleUrls: ['./item-header.component.css']
})
export class ItemHeaderComponent implements OnInit {
@ViewChild(TemplateRef) public headerTemplate: TemplateRef<any>;
@Input() title:string = ''
}
Moving towards the app-item
component, minor template adjustments are necessary. By adopting a similar approach to the header component, you can retrieve the template for the item content.
<ng-template>
<ng-content select="app-item-content"t></ng-content>
<ng-template>
In the code, utilize the ViewChild decorator to obtain the content template as done previously. Since the header is a child component of the item, a slightly different yet analogous approach using the ContentChild decorator allows access to the header component and its corresponding template.
@Component({
selector: 'app-item',
templateUrl: './item.component.html',
styleUrls: ['./item.component.css']
})
export class ItemComponent implements OnInit {
@ViewChild(TemplateRef) public contentTemplate: TemplateRef<any>;
@ContentChild(ItemHeaderComponent) public itemHeader: ItemHeaderComponent;
}
With all essential components accessible, one can proceed to render the contents within the mat-tab
components. Within the template, include the mat-tab-group
alongside a mat-tab
for each app-item
component, utilizing the exposed templates for rendering.
<mat-tab-group>
<mat-tab *ngFor="let item of appItems">
<ng-template mat-tab-label>
<ng-container *ngTemplateOutlet="item.itemHeader.headerTemplate"></ng-container>
</ng-template>
<ng-container *ngTemplateOutlet="item.contentTemplate"></ng-container>
</mat-tab>
</mat-tab-group>
The process involves creating a tab for each item and populating them with content from the respective items. Notably, when handling headers, embedding the template within another ng-template
ensures proper recognition as header content with the mat-tab-label
directive included.
To incorporate all app-item
components within the wrapper component, leverage the ContentChildren decorator, which generates a list of contained components. Simply introduce a corresponding property in the code, allowing Angular to manage the rest effortlessly.
@Component({
selector: 'app-wrapper',
templateUrl: './wrapper.component.html',
styleUrls: ['./wrapper.component.css']
})
export class WrapperComponent implements OnInit {
@ContentChildren(ItemComponent) public appItems: QueryList<ItemComponent>;
}
An example showcasing the functionality can be found in a modified version of your StackBlitz, available at this link.