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:
- Reusable tab structure that dynamically loads components.
- Uses Angular Directives to handle dynamic tab creation.
- Lazy loading for efficiency.
- 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.