Skip to main content

Overview

The HeaderComponent provides a consistent top navigation bar across all pages of the application. It displays dynamic page titles based on the current route and includes user information and search functionality.

Component Definition

selector
string
default:"app-header"
The CSS selector used to include this component in templates
standalone
boolean
default:true
This is a standalone component that can be imported directly
imports
array
Dependencies: CommonModule

Source Code Location

File: src/app/header/header.ts:8
import { Component, inject, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map, mergeMap } from 'rxjs/operators';
import { toSignal } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-header',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './header.html',
  styleUrl: './header.css'
})
export class HeaderComponent {
  private readonly router = inject(Router);
  private readonly activatedRoute = inject(ActivatedRoute);

  public readonly title = toSignal(
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd),
      map(() => this.activatedRoute),
      map(route => {
        while (route.firstChild) {
          route = route.firstChild;
        }
        return route;
      }),
      mergeMap(route => route.data),
      map(data => data['title'] || 'Odontologia')
    ),
    { initialValue: 'Odontologia' }
  );
}

Properties

title

title
Signal<string>
default:"'Odontologia'"
A reactive signal containing the current page title derived from route data
The title property uses Angular’s toSignal() function to convert the router’s event stream into a signal. It:
  1. Listens for NavigationEnd events
  2. Traverses to the deepest child route
  3. Extracts the title from route data
  4. Falls back to “Odontologia” if no title is defined
Implementation: src/app/header/header.ts:18-32

Template Structure

The header is divided into two main sections:

Left Section (header-info)

welcome-msg
span
Displays a personalized greeting: “¡Hola, Dr. Admin! 👋”
section-title
h1
Shows the dynamic page title using signal interpolation: {{ title() }}

Right Section (header-actions)

Search input with icon for searching patients and appointments (non-functional in current implementation)
user-snippet
div
User avatar displaying initials (“AD”) and notification bell icon

Usage

The HeaderComponent is included in the main app layout:
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Menu } from './menu/menu';
import { HeaderComponent } from './header/header';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet, Menu, HeaderComponent],
  templateUrl: './app.html',
  styleUrl: './app.css'
})
export class App {
  // App logic
}

Setting Route Titles

To set the page title for a route, add a title property to the route data:
import { Routes } from '@angular/router';
import { Patient } from './patient/patient';
import { Appointment } from './appointment/appointment';

export const routes: Routes = [
  {
    path: 'patient',
    component: Patient,
    data: { title: 'Pacientes' }
  },
  {
    path: 'citas',
    component: Appointment,
    data: { title: 'Citas' }
  }
];

Styling

The header uses scoped CSS with the following structure:
  • header-container: Flexbox container with space-between alignment
  • header-info: Left section with vertical layout
  • header-actions: Right section with horizontal layout

Dependency Injection Pattern

The component uses Angular’s modern inject() function instead of constructor injection:
private readonly router = inject(Router);
private readonly activatedRoute = inject(ActivatedRoute);
This approach is more concise and works seamlessly with standalone components.

RxJS Integration

The component demonstrates reactive programming with RxJS operators:
1

Filter events

Only process NavigationEnd events using the filter operator
2

Navigate route tree

Find the deepest child route using map transformations
3

Extract data

Use mergeMap to access route data observables
4

Convert to signal

Transform the observable stream into a signal with toSignal

Customization

Change Welcome Message

Edit the welcome message in header.html:3:
<span class="welcome-msg">¡Hola, {{ userName }}! 👋</span>

Add User Avatar Logic

Replace static initials with dynamic user data:
export class HeaderComponent {
  private readonly userService = inject(UserService);
  protected readonly userInitials = computed(() => {
    const user = this.userService.currentUser();
    return user ? user.initials : 'AD';
  });
}

Implement Search Functionality

Add search logic to the component:
protected searchQuery = signal('');

protected onSearch(event: Event): void {
  const input = event.target as HTMLInputElement;
  this.searchQuery.set(input.value);
  // Implement search logic
}

Menu

Sidebar navigation component

Architecture

Main application structure

Build docs developers (and LLMs) love