← Back to Tutorials Chapter 14

Libraries & Advanced

Angular integrates deeply with RxJS for reactive programming and introduces Signals for fine-grained reactivity. This chapter explores advanced libraries, authentication, internationalization, and standalone components.

RxJS

RxJS (Reactive Extensions for JavaScript) is the foundation of Angular's asynchronous and event-based programming model.

Core Types

Operators

Operators transform, filter, and combine Observable streams.

import { of, fromEvent } from 'rxjs';
import { map, filter, debounceTime, switchMap } from 'rxjs/operators';

of(1, 2, 3, 4, 5).pipe(
  filter(x => x % 2 === 0),
  map(x => x * 10)
).subscribe(console.log); // 20, 40

// Search input with debounce
fromEvent(input, 'input').pipe(
  debounceTime(300),
  switchMap(() => this.searchService.search(input.value))
).subscribe(results => this.results = results);
switchMap cancels the previous inner observable when a new value arrives — ideal for typeahead searches.

Angular Signals

Signals provide a new reactive primitive for Angular. They are simpler than RxJS for state management and integrate deeply with change detection.

import { signal, computed, effect, input, output } from '@angular/core';

const count = signal(0);
const doubled = computed(() => count() * 2);

effect(() => console.log('Count:', count()));

// In a component
export class CounterComponent {
  value = input(0);
  changed = output<number>();

  increment() {
    this.value.update(v => v + 1);
    this.changed.emit(this.value());
  }
}

Authentication (JWT)

JSON Web Tokens (JWT) are commonly used for stateless authentication. Store tokens in localStorage and attach them via HTTP interceptors.

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = localStorage.getItem('token');
    if (token) {
      req = req.clone({
        headers: req.headers.set('Authorization', `Bearer ${token}`)
      });
    }
    return next.handle(req);
  }
}

@Injectable({ providedIn: 'root' })
export class AuthService {
  private user = signal<User | null>(null);
  isLoggedIn = computed(() => this.user() !== null);

  login(credentials: Credentials) {
    return this.http.post<{ token: string }>('/api/login', credentials).pipe(
      tap(res => {
        localStorage.setItem('token', res.token);
        this.user.set(this.decodeToken(res.token));
      })
    );
  }
}

Route Guards

Protect routes using CanActivate guard.

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (!this.auth.isLoggedIn()) {
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}

Internationalization (i18n)

Use @angular/localize to translate your application into multiple languages.

ng add @angular/localize

// In template
<h1 i18n="Greeting|An introduction greeting">Hello!</h1>

// Extract messages
ng extract-i18n --output-path src/locale

Standalone Components

Standalone components eliminate the need for NgModule. Use standalone: true and bootstrapApplication.

@Component({
  standalone: true,
  imports: [CommonModule, RouterModule],
  template: `<h1>Standalone!</h1>`
})
export class AppComponent {}

// main.ts
bootstrapApplication(AppComponent, {
  providers: [provideHttpClient(), provideRouter(routes)]
});

Web Workers

Run CPU-intensive tasks off the main thread with web workers.

const worker = new Worker(new URL('./app.worker', import.meta.url));
worker.postMessage({ data: heavyArray });
worker.onmessage = ({ data }) => console.log(data);

SSR with Angular Universal

Angular Universal enables server-side rendering for better SEO and initial load performance.

ng add @nguniversal/express-engine
Angular advanced libraries
Practice Task: Refactor a routed Angular module into standalone components. Replace the main module bootstrap with bootstrapApplication and configure the router provider. Add an authentication guard to protect a dashboard route.