Explain

How to dynamically change header based on AngularJS partial view?

When building single-page applications in AngularJS, it’s common to display different partial views based on the route or state. Often, you’ll want your application’s header (whether that’s the <title> tag, a navigation bar, or a header <div>) to change dynamically depending on which partial is currently being shown. Below are a few ways to achieve this.

1. Change the Page <title> Dynamically

If by “header” you mean the HTML page title (in the <head> section), you can set it in your route configuration and update it whenever the route changes.

Step 1: Add a Title Property in Your Route Configuration

For ngRoute:

angular.module('myApp', ['ngRoute'])
  .config(function($routeProvider) {
    $routeProvider
      .when('/home', {
        templateUrl: 'views/home.html',
        controller: 'HomeController',
        // Custom property for the page title
        title: 'Home Page'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutController',
        title: 'About Us'
      })
      .otherwise({ redirectTo: '/home' });
  });

Step 2: Listen for $routeChangeSuccess and Update $rootScope Title

You can update $rootScope.pageTitle on each route change and then bind it in your main index.html.

angular.module('myApp')
  .run(function($rootScope, $route) {
    $rootScope.$on('$routeChangeSuccess', function(event, current) {
      // current might be undefined if no matching route
      if (current.$$route && current.$$route.title) {
        $rootScope.pageTitle = current.$$route.title;
      } else {
        $rootScope.pageTitle = 'Default Title';
      }
    });
  });

Step 3: Bind the Title in Your index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <title>{{ pageTitle }}</title>
  <!-- other head content -->
</head>
<body>
  <ng-view></ng-view>
</body>
</html>

Now, whenever you navigate to a new route, $rootScope.pageTitle updates based on the route’s custom property, and the <title> tag reflects that change.

2. Change a Navigation Bar or Header <div> Dynamically

If your “header” refers to a navigation bar or a top <div> in your layout, you can do something similar:

  1. Store the desired header text, icons, or styles in your route config or in a service.
  2. Listen to route change events.
  3. Update a $rootScope or a shared service property that your main layout controller watches.

Recommended Courses

Example Using $routeProvider

$routeProvider
  .when('/dashboard', {
    templateUrl: 'views/dashboard.html',
    controller: 'DashboardController',
    headerInfo: { title: 'Dashboard', icon: 'dashboard-icon.png' }
  })
  .when('/profile', {
    templateUrl: 'views/profile.html',
    controller: 'ProfileController',
    headerInfo: { title: 'User Profile', icon: 'user-icon.png' }
  });

In your run block or a top-level controller, watch $routeChangeSuccess:

.run(function($rootScope) {
  $rootScope.$on('$routeChangeSuccess', function(event, current) {
    if (current.$$route && current.$$route.headerInfo) {
      $rootScope.headerTitle = current.$$route.headerInfo.title;
      $rootScope.headerIcon = current.$$route.headerInfo.icon;
    } else {
      $rootScope.headerTitle = 'My App';
      $rootScope.headerIcon = 'default-icon.png';
    }
  });
});

In your main layout (e.g., index.html or a root partial):

<header>
  <img ng-src="{{ headerIcon }}" alt="Header Icon">
  <h1>{{ headerTitle }}</h1>
</header>
<ng-view></ng-view>

This way, each partial view can define how the header looks, and you only have one header element in the layout.

3. Using UI-Router (If You’re Not Using ngRoute)

If your project uses UI-Router (another popular router for AngularJS), the concept is similar but with states instead of $routeProvider. For each state, define custom data or a resolve property:

$stateProvider
  .state('home', {
    url: '/home',
    templateUrl: 'views/home.html',
    controller: 'HomeController',
    data: {
      headerTitle: 'Home Page',
      headerIcon: 'home-icon.png'
    }
  })
  .state('about', {
    url: '/about',
    templateUrl: 'views/about.html',
    controller: 'AboutController',
    data: {
      headerTitle: 'About Us'
    }
  });

Then in a run block or a top-level controller:

.run(function($rootScope, $state) {
  $rootScope.$on('$stateChangeSuccess', function(event, toState) {
    if (toState.data && toState.data.headerTitle) {
      $rootScope.headerTitle = toState.data.headerTitle;
      $rootScope.headerIcon = toState.data.headerIcon || 'default-icon.png';
    } else {
      $rootScope.headerTitle = 'My App';
      $rootScope.headerIcon = 'default-icon.png';
    }
  });
});

The <header> binding remains the same:

<header>
  <img ng-src="{{ headerIcon }}">
  <h1>{{ headerTitle }}</h1>
</header>
<ui-view></ui-view> <!-- UI-Router's equivalent of <ng-view> -->

Best Practices

  1. Single Source of Truth
    Maintain the “header info” in the route config or UI-Router state so that each partial knows exactly how the header should look.

  2. Minimize Global Scope
    Use $rootScope sparingly (only if your header is truly global). If you have a layout controller, consider storing the header info there, and inject it into child views as needed.

  3. Avoid Repeated Elements
    Don’t duplicate <header> in every partial. Instead, keep one header in the layout (e.g., index.html), and let each partial define the data that modifies that header.

  4. Fallbacks
    Provide fallback values (like 'My App', a default icon, etc.) so if a route does not define custom header data, the UI remains consistent.

Going Beyond: Mastering AngularJS & System Design

Setting up a dynamic header is just one piece of building a robust single-page application in AngularJS. To deepen your expertise, check out the following resources from DesignGurus.io:

If you’d like personalized feedback from ex-FAANG engineers, check out:

And for free tutorials, visit the DesignGurus.io YouTube channel.

Final Thoughts

To dynamically change the header based on which AngularJS partial view is displayed:

  1. Attach data (like a title or icon) to each route/state.
  2. Listen for route/state changes in a run block or layout controller.
  3. Update a shared property (e.g., $rootScope.headerTitle) used by your main header.

By keeping your header in one place (e.g., index.html or a root component) and letting each partial define its own header data, you maintain a clean, modular design that’s easy to update as your AngularJS app evolves.