Creating a dynamic tab component using directives

Loading

Creating a Dynamic Tab Component using Directives in Angular requires a deep understanding of directives, dynamic components, dependency injection, and Angular’s component lifecycle. In this guide, I will take you step by step through the process of building a dynamic tab system using Angular directives.


Step 1: Understanding Dynamic Tabs

Dynamic tabs allow users to navigate between different sections without reloading the page. Each tab represents a component that can be dynamically loaded based on user interaction.

Features of Our Tab System:

  1. Reusable tab structure that dynamically loads components.
  2. Uses Angular Directives to handle dynamic tab creation.
  3. Lazy loading for efficiency.
  4. Allows adding and removing tabs dynamically.

Step 2: Setting Up the Angular Project

Ensure that you have Node.js and Angular CLI installed. If not, install them:

npm install -g @angular/cli

Now, create a new Angular project:

ng new dynamic-tabs
cd dynamic-tabs
ng serve

Step 3: Creating the Tab Components

We will create three example components that will act as different tabs.

ng generate component tabs/tab1
ng generate component tabs/tab2
ng generate component tabs/tab3

Each component will contain some sample content:

tab1.component.html

<h2>Tab 1</h2>
<p>This is content for Tab 1.</p>

tab2.component.html

<h2>Tab 2</h2>
<p>This is content for Tab 2.</p>

tab3.component.html

<h2>Tab 3</h2>
<p>This is content for Tab 3.</p>

Step 4: Creating the Tab Directive

We will use ViewContainerRef and ComponentFactoryResolver to dynamically load components.

Create a directive:

ng generate directive directives/tab-host

Modify the tab-host.directive.ts file:

tab-host.directive.ts

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
selector: '[appTabHost]'
})
export class TabHostDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}

Explanation:

  • @Directive({ selector: '[appTabHost]' }): This directive will be applied to an element that acts as a placeholder for dynamic components.
  • ViewContainerRef: This will be used to insert components dynamically.

Step 5: Creating a Tab Service

We will create a service to manage tab components dynamically.

ng generate service services/tab

Modify tab.service.ts:

tab.service.ts

import { Injectable, ComponentFactoryResolver, ViewContainerRef, Type } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class TabService {
private viewContainerRef!: ViewContainerRef;

setViewContainerRef(viewContainerRef: ViewContainerRef) {
this.viewContainerRef = viewContainerRef;
}

loadComponent(component: Type<any>) {
this.viewContainerRef.clear();
const factory = this.viewContainerRef.createComponent(component);
return factory;
}
}

Explanation:

  • setViewContainerRef(viewContainerRef: ViewContainerRef): Stores the reference of the container where components will be loaded.
  • loadComponent(component: Type<any>): Dynamically loads the selected component.

Step 6: Creating the Tab Container Component

Create a Tab Container Component to manage tab switching.

ng generate component components/tab-container

Modify the tab-container.component.html:

tab-container.component.html

<div class="tab-buttons">
<button *ngFor="let tab of tabs" (click)="loadTab(tab.component)">{{ tab.title }}</button>
</div>

<div class="tab-content">
<ng-container appTabHost></ng-container>
</div>

Modify the tab-container.component.ts:

tab-container.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { TabService } from '../../services/tab.service';
import { Tab1Component } from '../../tabs/tab1/tab1.component';
import { Tab2Component } from '../../tabs/tab2/tab2.component';
import { Tab3Component } from '../../tabs/tab3/tab3.component';
import { TabHostDirective } from '../../directives/tab-host.directive';

@Component({
selector: 'app-tab-container',
templateUrl: './tab-container.component.html',
styleUrls: ['./tab-container.component.css'],
})
export class TabContainerComponent implements AfterViewInit {
@ViewChild(TabHostDirective, { static: true }) tabHost!: TabHostDirective;

tabs = [
{ title: 'Tab 1', component: Tab1Component },
{ title: 'Tab 2', component: Tab2Component },
{ title: 'Tab 3', component: Tab3Component },
];

constructor(private tabService: TabService) {}

ngAfterViewInit() {
this.tabService.setViewContainerRef(this.tabHost.viewContainerRef);
this.loadTab(Tab1Component);
}

loadTab(component: any) {
this.tabService.loadComponent(component);
}
}

Explanation:

  • Uses ViewChild to get the directive reference.
  • Dynamically loads components based on button clicks.
  • Automatically loads the first tab on initialization.

Step 7: Styling the Tabs

Modify tab-container.component.css:

.tab-buttons {
display: flex;
gap: 10px;
margin-bottom: 10px;
}

button {
padding: 10px;
border: none;
background-color: #007bff;
color: white;
cursor: pointer;
}

button:hover {
background-color: #0056b3;
}

.tab-content {
padding: 20px;
border: 1px solid #ddd;
}

Step 8: Adding Tab Container to App Component

Modify app.component.html:

<app-tab-container></app-tab-container>

Modify app.module.ts:

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TabContainerComponent } from './components/tab-container/tab-container.component';
import { Tab1Component } from './tabs/tab1/tab1.component';
import { Tab2Component } from './tabs/tab2/tab2.component';
import { Tab3Component } from './tabs/tab3/tab3.component';
import { TabHostDirective } from './directives/tab-host.directive';

@NgModule({
declarations: [
AppComponent,
TabContainerComponent,
Tab1Component,
Tab2Component,
Tab3Component,
TabHostDirective,
],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

Step 9: Running the Application

Run the application using:

ng serve

Now, you will see dynamic tabs that switch between different components without reloading the page.

Leave a Reply

Your email address will not be published. Required fields are marked *