Lesson 4: Advanced Angular Concepts
Lesson 4: Advanced Angular Concepts
This lesson explores Angular Animations, WebSockets, Directives with Inputs, Multi-Step Forms, and Custom Validators.
Example 1: Angular Animations (Fade In & Out)
This example demonstrates Angular animations for fading elements in and out.
Code:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, BrowserAnimationsModule],
bootstrap: [AppComponent]
})
export class AppModule { }
// app.component.ts
import { Component } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('fade', [
state('visible', style({ opacity: 1 })),
state('hidden', style({ opacity: 0 })),
transition('visible <=> hidden', animate('500ms ease-in-out'))
])
]
})
export class AppComponent {
isVisible = true;
toggle() {
this.isVisible = !this.isVisible;
}
}
<!-- app.component.html -->
<button (click)="toggle()">Toggle Fade</button>
<div [@fade]="isVisible ? 'visible' : 'hidden'" class="box">Hello, Angular!</div>
/* app.component.css */
.box {
width: 200px;
height: 100px;
background-color: lightblue;
text-align: center;
line-height: 100px;
margin-top: 20px;
}
Explanation:
Animations Module:
BrowserAnimationsModule
is imported to enable Angular animations.Trigger & States:
trigger('fade')
defines animation states (visible
,hidden
).Transitions:
transition('visible <=> hidden')
animates state changes.Binding Animation:
[@fade]
dynamically controls the element's visibility.Smooth Effects:
animate('500ms ease-in-out')
ensures fluid transitions.
Example 2: Real-Time Data with WebSockets
Implements WebSockets for real-time chat messages.
Code:
// websocket.service.ts
import { Injectable } from '@angular/core';
import { Observable, Subject, WebSocketSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class WebSocketService {
private socket$: WebSocketSubject<string>;
constructor() {
this.socket$ = new WebSocketSubject('wss://echo.websocket.org');
}
sendMessage(message: string) {
this.socket$.next(message);
}
getMessages(): Observable<string> {
return this.socket$.asObservable();
}
}
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { WebSocketService } from './websocket.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
messages: string[] = [];
newMessage = '';
constructor(private wsService: WebSocketService) {}
ngOnInit() {
this.wsService.getMessages().subscribe(msg => {
this.messages.push(msg);
});
}
sendMessage() {
this.wsService.sendMessage(this.newMessage);
this.newMessage = '';
}
}
<!-- app.component.html -->
<input [(ngModel)]="newMessage" placeholder="Type a message">
<button (click)="sendMessage()">Send</button>
<ul>
<li *ngFor="let msg of messages">{{ msg }}</li>
</ul>
Explanation:
WebSocketSubject: Handles WebSocket connections reactively.
Observable Messages:
getMessages()
returns an observable stream of messages.Two-Way Data Flow:
sendMessage()
sends data to the WebSocket server.Dynamic UI Update: New messages appear in the list in real time.
Reusable Service:
WebSocketService
can be injected anywhere.
Example 3: Directive with Input Property
A custom directive that changes text color dynamically.
Code:
// color.directive.ts
import { Directive, ElementRef, Input, OnChanges } from '@angular/core';
@Directive({
selector: '[appColor]'
})
export class ColorDirective implements OnChanges {
@Input() appColor = 'black';
constructor(private el: ElementRef) {}
ngOnChanges() {
this.el.nativeElement.style.color = this.appColor;
}
}
<!-- app.component.html -->
<p appColor="red">This text is red</p>
<p appColor="blue">This text is blue</p>
<p appColor="green">This text is green</p>
Explanation:
Custom Directive:
@Directive()
creates a reusable directive.Dynamic Input:
@Input() appColor
allows dynamic color changes.ElementRef Manipulation: Directly modifies the host element’s style.
Lifecycle Hook:
ngOnChanges()
updates color whenappColor
changes.Versatility: Works on any text element dynamically.
Example 4: Multi-Step Form (Stepper)
Creates a multi-step form for user registration.
Code:
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
step = 1;
user = { name: '', email: '', password: '' };
next() {
this.step++;
}
previous() {
this.step--;
}
submit() {
console.log('User Data:', this.user);
}
}
<!-- app.component.html -->
<div *ngIf="step === 1">
<h2>Step 1: Enter Name</h2>
<input [(ngModel)]="user.name" placeholder="Name">
<button (click)="next()">Next</button>
</div>
<div *ngIf="step === 2">
<h2>Step 2: Enter Email</h2>
<input [(ngModel)]="user.email" placeholder="Email">
<button (click)="previous()">Back</button>
<button (click)="next()">Next</button>
</div>
<div *ngIf="step === 3">
<h2>Step 3: Enter Password</h2>
<input type="password" [(ngModel)]="user.password" placeholder="Password">
<button (click)="previous()">Back</button>
<button (click)="submit()">Submit</button>
</div>
Explanation:
Step Management:
step
variable controls which form step is displayed.Two-Way Binding:
[(ngModel)]
updatesuser
object properties dynamically.Navigation Control:
next()
andprevious()
switch between steps.Conditional Rendering:
*ngIf="step === x"
ensures step-wise form flow.Form Submission:
submit()
logs user details when completed.
Example 5: Custom Form Validator (Password Match)
A custom validator ensures passwords match.
Code:
// password-match.directive.ts
import { AbstractControl, ValidatorFn } from '@angular/forms';
export function passwordMatchValidator(): ValidatorFn {
return (control: AbstractControl) => {
const password = control.get('password')?.value;
const confirmPassword = control.get('confirmPassword')?.value;
return password === confirmPassword ? null : { mismatch: true };
};
}
// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { passwordMatchValidator } from './password-match.directive';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
password: ['', Validators.required],
confirmPassword: ['', Validators.required]
}, { validators: passwordMatchValidator() });
}
}
<!-- app.component.html -->
<form [formGroup]="form">
<input type="password" formControlName="password" placeholder="Password">
<input type="password" formControlName="confirmPassword" placeholder="Confirm Password">
<div *ngIf="form.errors?.mismatch">Passwords do not match!</div>
</form>
Explanation:
Custom Validator:
passwordMatchValidator()
ensures both fields match.FormGroup Validation: Applied to entire form, not individual fields.
Dynamic Error Display:
*ngIf="form.errors?.mismatch"
conditionally shows validation errors.FormBuilder Usage: Simplifies form control creation.
Security Enhancement: Prevents mismatched password submissions.
These five Angular examples cover animations, WebSockets, directives, multi-step forms, and validation, essential for advanced applications