Skip to main content

Command Palette

Search for a command to run...

Lesson 6: Advanced Angular Features.

Published
4 min read

Lesson 6: Advanced Angular Features

This lesson covers State Management with NgRx Effects, Reusable Modal Components, Dynamic Form Fields, Theme Switching with CSS Variables, and Debounced Search Input.


Example 1: State Management with NgRx Effects

Implements NgRx Effects to handle asynchronous API calls.

Code:

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { userReducer } from './user.reducer';
import { UserEffects } from './user.effects';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    StoreModule.forRoot({ users: userReducer }),
    EffectsModule.forRoot([UserEffects])
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
// user.actions.ts
import { createAction, props } from '@ngrx/store';

export const loadUsers = createAction('[User] Load Users');
export const loadUsersSuccess = createAction('[User] Load Users Success', props<{ users: any[] }>());
// user.reducer.ts
import { createReducer, on } from '@ngrx/store';
import { loadUsersSuccess } from './user.actions';

export const initialState: any[] = [];

export const userReducer = createReducer(
  initialState,
  on(loadUsersSuccess, (state, { users }) => users)
);
// user.effects.ts
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { HttpClient } from '@angular/common/http';
import { loadUsers, loadUsersSuccess } from './user.actions';
import { map, switchMap } from 'rxjs/operators';

@Injectable()
export class UserEffects {
  constructor(private actions$: Actions, private http: HttpClient) {}

  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadUsers),
      switchMap(() => this.http.get<any[]>('https://jsonplaceholder.typicode.com/users')
        .pipe(map(users => loadUsersSuccess({ users }))))
    )
  );
}

Explanation:

  1. NgRx Store & Effects: Uses NgRx to manage state and side effects efficiently.

  2. Asynchronous API Call: UserEffects fetches users from an API.

  3. Action Handling: loadUsers triggers API fetch, loadUsersSuccess updates the state.

  4. Immutable State: NgRx ensures state updates follow best practices.

  5. Performance Optimization: Efficiently handles large-scale applications.


Example 2: Reusable Modal Component

Creates a reusable modal component.

Code:

// modal.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent {
  @Input() title = 'Modal Title';
  @Output() close = new EventEmitter<void>();

  closeModal() {
    this.close.emit();
  }
}
<!-- modal.component.html -->
<div class="overlay">
  <div class="modal">
    <h2>{{ title }}</h2>
    <ng-content></ng-content>
    <button (click)="closeModal()">Close</button>
  </div>
</div>
/* modal.component.css */
.overlay {
  position: fixed;
  top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex; justify-content: center; align-items: center;
}
.modal {
  background: white; padding: 20px; border-radius: 8px;
}
<!-- app.component.html -->
<button (click)="isModalOpen = true">Open Modal</button>
<app-modal *ngIf="isModalOpen" title="My Modal" (close)="isModalOpen = false">
  <p>This is modal content.</p>
</app-modal>

Explanation:

  1. Reusable Component: app-modal can be used anywhere in the app.

  2. Dynamic Content: ng-content allows inserting any content inside the modal.

  3. Two-Way Communication: @Input() sets title, @Output() triggers closing.

  4. CSS Styling: Overlay ensures smooth modal display.

  5. Conditional Rendering: *ngIf="isModalOpen" controls modal visibility.


Example 3: Dynamic Form Fields

Adds form fields dynamically.

Code:

// app.component.ts
import { Component } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      items: this.fb.array([])
    });
  }

  get items() {
    return this.form.get('items') as FormArray;
  }

  addItem() {
    this.items.push(this.fb.control('', Validators.required));
  }

  removeItem(index: number) {
    this.items.removeAt(index);
  }
}
<!-- app.component.html -->
<form [formGroup]="form">
  <div formArrayName="items">
    <div *ngFor="let item of items.controls; let i = index">
      <input [formControlName]="i">
      <button (click)="removeItem(i)">Remove</button>
    </div>
  </div>
  <button (click)="addItem()">Add Item</button>
</form>

Explanation:

  1. Dynamic Fields: FormArray allows adding/removing input fields dynamically.

  2. Validation: Each input requires a value before form submission.

  3. Two-Way Binding: Updates instantly when adding/removing fields.

  4. Scalability: Supports unlimited form fields.

  5. Simplified UI: Uses *ngFor to dynamically create inputs.


Example 4: Theme Switching with CSS Variables

Implements dark/light mode switching.

Code:

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  toggleTheme() {
    document.body.classList.toggle('dark-mode');
  }
}
<!-- app.component.html -->
<button (click)="toggleTheme()">Toggle Theme</button>
/* styles.css */
:root {
  --background: white;
  --text: black;
}

.dark-mode {
  --background: black;
  --text: white;
}

body {
  background-color: var(--background);
  color: var(--text);
  transition: 0.3s;
}

Explanation:

  1. CSS Variables: Uses --background and --text to store colors.

  2. Class Toggle: dark-mode applies dark theme dynamically.

  3. Smooth Transitions: Theme switches seamlessly with transition: 0.3s.

  4. Global Styling: Works across the entire application.

  5. Performance: No component re-rendering needed.


Example 5: Debounced Search Input

Delays search execution until the user stops typing.

Code:

// app.component.ts
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  searchControl = new FormControl('');

  constructor() {
    this.searchControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
      console.log('Search:', value);
    });
  }
}
<!-- app.component.html -->
<input [formControl]="searchControl" placeholder="Type to search...">

Explanation:

  1. Debounce Mechanism: Delays execution until user stops typing.

  2. RxJS Integration: Uses debounceTime(500) to optimize performance.

  3. Real-Time Search: Triggers API requests only when necessary.

  4. FormControl Usage: Simplifies handling input changes.

  5. Improves UX: Prevents unnecessary API calls.


These five Angular examples cover NgRx Effects, modals, dynamic forms, theme switching, and search debouncing, essential for modern web applications .

More from this blog

Programming , Big Data, DevOps, etc

271 posts

Programming , Big Data, DevOps, etc