Loading dynamic content within Angular Material tabs allows for a more customized and interactive user experience

I am currently working on creating a dynamic tab system using Angular Material: Tabs. I have encountered an issue with loading content on tabs after the initial one, where the functionality only works when the first tab is loaded.

Below you can see the tab group structure. The tabs are generated from an array of 'tabs' received from a service. On the tab group, there is a change event that should dynamically load a component for the active tab when it changes.

<mat-tab-group *ngIf="tabs.length >= 1" #shiftplanningtabgroup (selectedTabChange)="selectedTabChange($event);">
    <mat-tab *ngFor="let tab of tabs; let idx = index;" [disabled]="tab.disabled">
        <ng-template mat-tab-label>
            <div class="ava-mat-tab-label font-size-12" fxLayout="row" fxLayoutGap="12px" fxLayoutAlign="center end">
                <mat-checkbox [checked]="tab.active" [disabled]="tab.disabled" (change)="checkboxStateChange($event, idx);"></mat-checkbox>
                <label class="cursor-pointer">{{ tab.label }}</label>
            </div>
        </ng-template>
        <div class="tab-content">
            <ng-template #tabHost></ng-template>
        </div>
    </mat-tab>
</mat-tab-group>

The event handler for 'selectedTabChange':

public selectedTabChange(event: MatTabChangeEvent): void {
  this.loadTabContent(event.index);
}

The method 'loadTabContent':

private loadTabContent(index: number): void {

  this.container.clear();

  const factory = this.componentFactoryResolver.resolveComponentFactory(AvaShiftPlanningTabContentComponent);

  const componentRef = this.container.createComponent<AvaShiftPlanningTabContentComponent>(factory);
  (componentRef.instance as AvaShiftPlanningTabContentComponent).loading = true;
  (componentRef.instance as AvaShiftPlanningTabContentComponent).tab = this.tabs[index];
  (componentRef.instance as AvaShiftPlanningTabContentComponent).tabLoadingCompleted.subscribe((value: any) => {
    this.tabLoadingComplete(value);
  });
}

And the reference to #tabHost:

@ViewChild('tabHost', { read: ViewContainerRef }) container: ViewContainerRef;

This setup works perfectly fine for the first tab. However, when adding more than one tab, the subsequent tabs do not display any content even though the component is being accessed upon tab change. It seems like the content for the dynamically loaded component is not rendered properly.

Could this be a limitation of Angular Material: Tabs or could there be something wrong with the approach I am taking to load the component?

Answer №1

I wanted to share my approach:

Even though this answer is delayed, I decided to provide some assistance since I stumbled upon it.

         <mat-tab-group (selectedIndexChange)="selected.setValue($event)"
                       [selectedIndex]="selected.value" animationDuration="0"
                       class="h-100 w-100">
            <mat-tab *ngFor="let tab of tabs; let index = index">
                <ng-template class="w-100" mat-tab-label>
                    {{ tab.label }}
                    <mat-icon (click)="removeTab(index)" class="float-end">cancel</mat-icon>
                </ng-template>
                <ng-template #frame style="max-width: 100%;"></ng-template> // <-- notice here
            </mat-tab>
        </mat-tab-group>

In order for the frame to function properly, it should be ViewChildren instead of ViewChild due to multiple items needing separate viewContainerRefs.

@ViewChildren('frame', { read: ViewContainerRef }) frame: QueryList<ViewContainerRef>;

When adding new items:

    this.tabs.push(action);

    if (selectAfterAdding) {
        this.selected.setValue(this.tabs.length - 1);
    }

To dynamically load content, consider using the Component Factory Resolver which can be found here.

I hope this explanation proves helpful to those in need.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for launching a stackblitz project

Apologies for the novice question. As a beginner in Angular (and StackBlitz), I have created a StackBlitz project to seek assistance on an Angular topic (reactive forms). However, I am unable to run it. Can anyone guide me on how to do so? Thank you. ...

Is it possible to have unique styles for individual tabs in a mat-tab-group using Angular Material?

Is it possible to have different text colors for each tab in a mat-tab-group and change the color of the blue outline at the bottom? If so, can you provide guidance on how to achieve this? Here is the default appearance of the tabs in my app: https://i.st ...

Simple steps to transform the "inputs" syntax into the "@Input" property decorator

There's this code snippet that I need to modify: @Component({ selector: 'control-messages', inputs: ['controlName: control'], template: `<div *ngIf="errorMessage !== null">{{errorMessage}}</div>` }) Is the ...

What is the best way to merge three arrays of data into a single iterable array?

I am working on a function that fetches data from an API. In this process, I execute a total of 3 queries, each returning an array of data. My goal is to combine these 3 arrays into a single iterable array, where the indexes correspond to the original a ...

Currently working on building an ecommerce application through a Udemy course but encountering some challenges with Spring Security implementation

I have a file called SecurityConfiguration.java in my project package com.luv2code.ecommerce.config; import org.springframework.context.annotation.Bean; import com.okta.spring.boot.oauth.Okta; import org.springframework.context.annotation.Configuration; i ...

Creating a custom data type for the Tanstack table filtering function

I developed a unique filter function specifically for enhancing the functionality of Tanstack Table by utilizing fuse.js. Despite my efforts, TypeScript consistently raises concerns when I try to define the type for my custom function. My goal is to alig ...

The Angular performance may be impacted by the constant recalculation of ngStyle when clicking on various input fields

I am facing a frustrating performance issue. Within my component, I have implemented ngStyle and I would rather not rewrite it. However, every time I interact with random input fields on the same page (even from another component), the ngStyle recalculate ...

Encountering difficulty with retrieving information from a shared service on Angular 6

Attempting to pass JSON data from one component to another component (like parent to child) using a service. The service has two methods: setJsonData and getJsonData. Service Class import { Injectable } from '@angular/core'; @Injectable({ pr ...

The parameter type `SetStateAction<EventDetails[] | undefined>` does not allow for assigning arguments

I am currently facing an issue in a ReactJS project where I am trying to update state that was initially set up like this: const [eventsData, setEventsData] = useState<EventDetails[]>(); Every time I try to update the state using setEventsData(obj), ...

Creating TypeScript Classes - Defining a Collection of Objects as a Class Property

I'm trying to figure out the best approach for declaring an array of objects as a property in TypeScript when defining a class. I need this for a form that will contain an unspecified number of checkboxes in an Angular Template-Driven form. Should I ...

VueJs with typescript encounters issues with recursive child components, resulting in a warning stating "Unknown custom element" being thrown

I am currently working on a dynamic form that is generated by a DataTypeObject (dto). I have encountered an issue with a warning message while creating recursive components. This warning points to a list of components with the same type as their parent: ...

Struggling with establishing connection logic between two database tables using Prisma and JavaScript

I'm facing a perplexing logic problem that is eluding my understanding. Within the context of using next-connect, I have a function designed to update an entry in the database: .put(async (req, res) => { const data = req.body; const { dob ...

Make sure to verify the existence of a value before attempting to render it in Angular 4

I am currently working on a project that involves Angular 4. Here is an example of the code I am using : <div *ngFor="let item of results"> <p> {{item.location.city}} </p> <p> {{item.location.country}} </p> </div> T ...

Guide on setting up component from service to display toast notifications

I am looking to implement a global toast service in my application with custom styles and HTML for the toasts. Currently, I am using ng2-toastr. For example, let's say I have a component A which contains a button in its view: <button (click)="show ...

Is it possible to implement a feature in Angular and Bootstrap where the toggle menu can be closed by clicking anywhere on the page, rather than just the toggle button

I'm working on an Angular project where I've implemented a navbar component. The navbar is responsive and includes a toggle button that appears when the browser window is resized. This button allows users to hide or display the menus. One issue ...

Deleting the previous ion-view from DOM in Ionic v1 with Angular

I have been working on modifying an app built in Ionic v1. Within the app, there is a primary View titled 'Client's Profile' that contains links to two other Views: Support Request and Complaints. In the Support Request view, there is a Te ...

Sending an image in the body of an HTTP request using Angular 7

I'm currently in the process of developing an Angular application that captures an image from a webcam every second and sends it to a REST API endpoint for analysis. To achieve this, I have implemented an interval observable that captures video from t ...

Receiving an error in TypeScript stating that the property or data does not exist on the type for Vue props

I've recently integrated TypeScript into my Vue project, and now I'm encountering an error every time I try to access a value in props or data: 37:46 Property 'activity' does not exist on type '{ props: { activity: { type: ObjectC ...

Tips on navigating an array to conceal specific items

In my HTML form, there is a functionality where users can click on a plus sign to reveal a list of items, and clicking on a minus sign will hide those items. The code structure is as follows: <div repeat.for="categoryGrouping of categoryDepartm ...

Ensuring a child element fills the height of its parent container in React Material-UI

Currently, I am in the process of constructing a React Dashboard using MUI. The layout consists of an AppBar, a drawer, and a content area contained within a box (Please correct me if this approach is incorrect)... https://i.stack.imgur.com/jeJBO.png Unf ...