Nested view with ui-router

Hi All,

When creating single page applications, routing will be very important. We want our navigation to feel like a normal site and still not have our site refresh. UI-Router provides great flexibility and power when defining states and nested states in application.

AngularUI Router

The UI-Router is a routing framework for AngularJS built by the AngularUI team. It provides a different approach than ngRoute in that it changes your application views based on state of the application and not just the route URL.

Example

Let’s go with sample application which demonstrates ui-router with nested view as well as with multiple view.

Here are the complete file list which we are going to use:

- css
    - bootstrap.min.css         // Bootstrap v3.1.1

- js
    - angular-ui-router.min.js  // State-based routing for AngularJS @version v0.2.8
    - angular.js                // AngularJS v1.2.13
    - app.js                    // our angular code        

- index.html                    // will hold the main template for our app
- home.html                     // home page code
- partial-home-list.html        // injected into the home page
- about.html                    // about page code
- table-data.html               // re-usable table that we can place anywhere

Now let’s look index.html file as below:

<!DOCTYPE html>
<html>
<head>

    <!-- CSS (load bootstrap) -->
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <style>
    .navbar { border-radius:0; }
    </style>

    <!-- JS (load angular, ui-router, and our custom js file) -->
    <script src="js/angular.js"></script>
    <script src="js/angular-ui-router.min.js"></script>
    <script src="js/app.js"></script>
</head>

<!-- apply our angular app to our site -->
<body ng-app="routerApp">

    <!-- NAVIGATION -->
    <nav class="navbar navbar-inverse" role="navigation">
        <div class="navbar-header">
            <a class="navbar-brand" ui-sref="#">ui-router Demo</a>
        </div>
        <ul class="nav navbar-nav">
            <li><a ui-sref="home">Home</a></li>
            <li><a ui-sref="about">About</a></li>
        </ul>
    </nav>

    <!-- MAIN CONTENT -->
    <!-- THIS IS WHERE WE WILL INJECT OUR CONTENT ============================== -->
    <div class="container">
        <div ui-view="main"></div>
    </div>

    
</body>
</html>

We are using Bootstrap to help with our styling. Here you can notice that we also load up ui-router in addition to loading Angular. UI Router is separate from the Angular core, just like ngRoute is separate.

To point to a certain state of our application and generate href for particular state we are using ui-sref. In our index.html, we have used ui-sref in our navigation bar (Home link and About link).

Also, notice that we are using <div ui-view=“main”></div> instead of ngRoute’s <div ng-view></div>. Initially, I’m always forgot to use ui-view with ui-router and use ng-view. Then I’m wondering why my application not works :). So please keep this in mind :).

Now let’s look how we can create states. Let’s start up our Angular application now in app.js.

var routerApp = angular.module('routerApp', ['ui.router']);

routerApp.config(function($stateProvider, $urlRouterProvider) {
    
    $urlRouterProvider.otherwise('/home/list');
    
    $stateProvider
        
        // HOME STATES AND NESTED VIEWS ========================================
        .state('home', {
            url: '/home',
            views: {
                'main@': {
                    templateUrl: 'home.html'
                }
            }
        })
        
        // nested list with custom controller
        .state('home.list', {
            url: '/list',
            templateUrl: 'partial-home-list.html',
            controller: function($scope) {
                $scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
            }
        })
        
        // nested list with just some random string data
        .state('home.paragraph', {
            url: '/paragraph',
            template: 'I could sure use a drink right now.'
        })
        
        // ABOUT PAGE AND MULTIPLE NAMED VIEWS =================================
        .state('about', {
            url: '/about',
            views: {
                'main@': { templateUrl: 'about.html' },
                'columnOne@about': { template: 'Look I am a column!' },
                'columnTwo@about': { 
                    templateUrl: 'table-data.html',
                    controller: 'aboutController'
                }
            }
            
        });

});

routerApp.controller('aboutController', function($scope) {
    
    $scope.message = 'test';
   
    $scope.products = [
        {
            name: 'Product 1',
            price: 50
        },
        {
            name: 'Product 2',
            price: 10000
        },
        {
            name: 'Product 3',
            price: 20000
        }
    ];
    
});

Now we have created the routerApp that we already applied to our body in the index.html file.
Here we have a .state() for home and for about. In home, we are using the template file home.html.
Notice that while creating home state we have used views: { ‘main@’: { templateUrl: ‘home.html’ } }. This is because we have specified the name of ui-view, main in index.html. If you don’t want to specify the view name then you not need to specify views while creating state and you can directly give templateUrl to the state.

Here in template home.html, you notice that we are using nested ui-view to load nested view. Please check in app.js that we have created two child states ‘home.list’ and ‘home.paragraph’.

To make one of the child state ‘home.list’ to load by default, we are using:

$urlRouterProvider.otherwise('/home/list');

For our About page (about.html), we are using two ui-view: columnOne and columnTwo.
Check our about.html:

<div class="jumbotron text-center">
    <h1>The About Page</h1>
    <p>This page demonstrates <span class="text-danger">multiple</span> and <span class="text-danger">named</span> views.</p>
</div>

<div class="row">

    <div class="col-sm-6">
        <div ui-view="columnOne"></div>
    </div>
    
    
    <div class="col-sm-6">
        <div ui-view="columnTwo"></div>
    </div>

    
</div>

Now let’s look at our app.js where we have created ‘about’ state as follows:

......
// nested list with just some random string data
        .state('home.paragraph', {
            url: '/paragraph',
            template: 'I could sure use a drink right now.'
        })
        
        // ABOUT PAGE AND MULTIPLE NAMED VIEWS =================================
        .state('about', {
            url: '/about',
            views: {
                'main@': { templateUrl: 'about.html' },
                'columnOne@about': { template: 'Look I am a column!' },
                'columnTwo@about': { 
                    templateUrl: 'table-data.html',
                    controller: 'aboutController'
                }
            }
            
        });
......

The multiple views concept very well explain in documents and I’d encourage taking a look at their examples.

This is an overview of the great tool that is UI-Router. The Angular applications can easily be created to be modular and extensible by using ui-router.

You can find out demo here. And find out demo application code on my github repository: example-ui-router

Advertisements

One thought on “Nested view with ui-router

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s