Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Using Nested States With The AngularJS UI-Router

TwitterFacebookRedditLinkedInHacker News

When coding, it is good practice to reduce duplicating your code as much as possible. When you build a website, multiple pages may be grouped with specific layouts that are used any number of times. You don’t want to duplicate your layout code across these pages.

A common thing to do in web design is to use templating. This exists similarly across many web languages, but in this example I’m going to demonstrate how to do this with AngularJS and the UI-Router extension.

To be specific we are going to accomplish the following:

  • Create a root layout that will span every page
  • Create a child layout that will be nested in the root layout. The child layout will contain a foundation to all settings pages
  • Create content views for each of the settings pages

With this knowledge you’d be able to create a multi-layout project. In this project, we are going to have the following directory and file structure:

templates
    settings.html
    account.html
    profile.html
js
    angular-ui-router.min.js
    app.js
index.html

Start by downloading the UI-Router library and including it in your project. Your index.html page should look something like this:

<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.min.js"></script>
        <script src="js/angular-ui-router.min.js"></script>
        <script src="js/app.js"></script>
    </head>
    <body ng-app="example">
        Index Level
        <div ui-view></div>
    </body>
</html>

Notice the index.html page has all our JavaScript and CSS includes. It also has the following two lines:

Index Level
<div ui-view></div>

I added the text Index Level to make it obvious that the index.html code is used in our page. It represents level one of three in our nesting line. The ui-view line is where the next layer will display.

Now let’s crack open the settings.html page. This page will pretty much just contain a menu system for navigating between settings pages. Often websites will have a separate UI system for settings pages, but yet it will keep a trend.

<h1>Settings Level</h1>
<hr/>
<a ui-sref="settings.profile">Show Profile</a>
<a ui-sref="settings.account">Show Account</a>
<div ui-view></div>

Notice the lines above. Two are responsible for loading the next level of nesting which is nesting level three. The last line is where level three will be loaded into. I threw a line of code in there to show us that the settings level was loaded.

Now we are going to add the code for the third level of nesting. Open profile.html and add the following lines:

Profile Level

Do the same for account.html, but this time add the following content:

Account Level

When a third level page is loaded it will show the root level, settings level, and content level content. So at this point we only did the UI work. We still need to code the JavaScript that will be responsible for tying everything together.

Open the app.js file and add the following code:

var example = angular.module("example", ['ui.router']);
example.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('settings', {
            url: '/settings',
            templateUrl: 'templates/settings.html'
        })
        .state('settings.profile', {
            url: '/profile',
            templateUrl: 'templates/profile.html',
            controller: 'ProfileController'
        })
        .state('settings.account', {
            url: '/account',
            templateUrl: 'templates/account.html',
            controller: 'AccountController'
        });
    $urlRouterProvider.otherwise('/settings/profile');
});

Time to break down what the above code means. Take a look at the following lines:

.state('settings', {
    url: '/settings',
    templateUrl: 'templates/settings.html'
})

The above state represents the settings level layout. It will never be called directly because it is nothing more than a layout. It cannot exist on its own in the scenario that we’re building.

.state('settings.profile', {
    url: '/profile',
    templateUrl: 'templates/profile.html',
    controller: 'ProfileController'
})

In the above code, notice in particular settings.profile. This has very specific meaning. It means that we are going to call the settings state as well as the profile state. It is how we accomplish nesting. States are object based so every time we add to the parent settings element it means we are going to render the page inside of it.

A video version of this article can be seen below.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.