angular-routing-ui-router
Javascript

AngularJS Routing Using UI-Router

AngularJS provides a great way to make single page applications. 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. We’ve already gone through Angular routing using the normal ngRoute method.

Today we’ll be looking at routing using UI-Router.

Overview

What is 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.

States vs URL Route

With this approach, your views and routes aren’t tied down to the site URL. This way, you can change the parts of your site using your routing even if the URL does not change.

When using ngRoute, you’d have to use ngInclude or other methods and this could get confusing. Now that all of your states, routing, and views are handled in your one .config(), this would help when using a top-down view of your application.

Sample Application

Let’s do something similar to the other routing tutorial we made. Let’s create a Home and About page.

Setup

Let’s get our application started. We will need a few files:


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

With our application structure figured out, let’s fill out some files.

<!-- index.html -->

<!DOCTYPE html>
<html>
<head>

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

    <!-- JS (load angular, ui-router, and our custom js file) -->
    <script src="http://code.angularjs.org/1.2.13/angular.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
    <script src="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="#">AngularUI Router</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 -->
<div class="container">

	<!-- THIS IS WHERE WE WILL INJECT OUR CONTENT ============================== -->
    <div ui-view></div>

</div>

</body>
</html>

There’s our HTML file. We will use Bootstrap to help with our styling. 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.

When creating a link with UI-Router, you will use ui-sref. The href will be generated from this and you want this to point to a certain state of your application. These are created in your app.js.

We also use <div ui-view></div> instead of ngRoute’s <div ng-view></div>.

Let’s start up our Angular application now in app.js.

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

routerApp.config(function($stateProvider, $urlRouterProvider) {
    
    $urlRouterProvider.otherwise('/home');
    
    $stateProvider
        
        // HOME STATES AND NESTED VIEWS ========================================
        .state('home', {
            url: '/home',
            templateUrl: 'partial-home.html'
        })
        
        // ABOUT PAGE AND MULTIPLE NAMED VIEWS =================================
        .state('about', {
            // we'll get to this in a bit       
        });
        
});

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 partial-home.html.

Let’s fill out our partial-home.html page so we can actually see information.

<!-- partial-home.html -->

<div class="jumbotron text-center">
    <h1>The Homey Page</h1>
    <p>This page demonstrates <span class="text-danger">nested</span> views.</p>    
</div>


Now we have our site! It doesn’t do much, but we have it.

angular-ui-router-home-first

With the boring normal stuff out of the way, let’s get to see why UI-Router has some pretty cool features.

Nested Views Home Page

Let’s look at how we can nest views. We’ll add two buttons to our home page and from there, we will want to show off different information based on what is clicked.

We’re going to add our buttons to partial-home.html and then go into our Angular file and see how we can change it to add nested views.

<!-- partial-home.html -->

<div class="jumbotron text-center">
    <h1>The Homey Page</h1>
    <p>This page demonstrates <span class="text-danger">nested</span> views.</p>  

    <a ui-sref=".list" class="btn btn-primary">List</a>
    <a ui-sref=".paragraph" class="btn btn-danger">Paragraph</a>
</div>

<div ui-view></div>


When linking to a nested view, we are going to use dot denotation: ui-sref=".list" and ui-sref=".paragraph". These will be defined in our Angular file and once we set it up there, we will inject into our new <div ui-view></div>.

In our app.js file, let’s create those nested states.

// app.js
...

$stateProvider

	// HOME STATES AND NESTED VIEWS ========================================
    .state('home', {
        url: '/home',
        templateUrl: 'partial-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.'
    })

...

Now the ui-sref we defined in home.html are linked to an actual state. With home.list and home.paragraph created, those links will now take the template provided and inject it into ui-view.

Last thing we need to do for the home page is define the partial-home-list.html file. We have also passed in a controller with a list of dogs that we will use in the template file.

<!-- partial-home-list.html -->

<ul>
    <li ng-repeat="dog in dogs">{{ dog }}</li>
</ul>


Now when we click List, it will inject our list of dogs into the template. Or if we click Paragraph, it will inject the string we gave.

angular-routing-ui-router-home-list

You can see how easy it is to change different parts of our application based on the state. We didn’t have to do any sort of work with ngInclude, ngShow, ngHide, or ngIf. This keeps our view files cleaner since all the work is in our app.js.

Let’s move on and see how we can have multiple views at once.

Multiple Views About Page

Having multiple views in your application can be very powerful. Maybe you have a sidebar on your site that has things like Popular Posts, Recent Posts, Users, or whatever. These can all be separated out and injected into our template. Each will have its own controller and template file so our app stays clean.

Having our application modular like this also lets us reuse data in different templates.

For our About page, let’s make two columns and have each have its own data. We will handle the view first and then look at how we can do this using UI-Router.

<!-- partial-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">

    <!-- COLUMN ONE NAMED VIEW -->
    <div class="col-sm-6">
        <div ui-view="columnOne"></div>
    </div>
    
    <!-- COLUMN TWO NAMED VIEW -->
    <div class="col-sm-6">
        <div ui-view="columnTwo"></div>
    </div>

</div>	


There we have multiple views. One is named columnOne and the other is columnTwo.

Why would somebody use this approach? That’s a good question. Are we creating an application that is too modularized and that could get confusing? Taken from the official UI-Router docs, here is a solid example of why you would have multiple named views. In their example, they show off different parts of an application. Each part has its own data, so having each with its own controllers and template files makes building something like this easy.

Now that our view is all created, let’s look at how we can apply template files and controllers to each view. We’ll go back to our app.js.

// app.js

...

    .state('about', {
        url: '/about',
        views: {

            // the main template will be placed here (relatively named)
            '': { templateUrl: 'partial-about.html' },

            // the child views will be defined here (absolutely named)
            'columnOne@about': { template: 'Look I am a column!' },

            // for column two, we'll define a separate controller 
            'columnTwo@about': { 
                templateUrl: 'table-data.html',
                controller: 'scotchController'
            }
        }
        
    });

}); // closes $routerApp.config()


// let's define the scotch controller that we call up in the about state
routerApp.controller('scotchController', function($scope) {
    
    $scope.message = 'test';
   
    $scope.scotches = [
        {
            name: 'Macallan 12',
            price: 50
        },
        {
            name: 'Chivas Regal Royal Salute',
            price: 10000
        },
        {
            name: 'Glenfiddich 1937',
            price: 20000
        }
    ];
    
});

...


angular-routing-ui-router-about

Just like that, our About page is ready to go. Now it may be confusing how we nested everything in the views for the about state. Why not define a templateUrl for the main page and then define the columns in a nested view object? The reason for this gives us a really great tool.

Relative vs Absolute Naming

UI-Router assigns every view to an absolute name. The structure for this is viewName@stateName. Since our main ui-view inside our about state, we gave it a blank name. The other two views because columnOne@about and columnTwo@about.

Having the naming scheme this way let’s us define multiple views inside a single state. The docs explain this concept very well and I’d encourage taking a look at their examples. Extremely powerful tools there.

Conclusion

This is an overview of the great tool that is UI-Router. The things you can do with it are incredible and when you look at your application as states instead of going the ngRoute option, Angular applications can easily be created to be modular and extensible.

Chris Sevilleja

Design, development, and anything in between that I find interesting.

View My Articles

Stay Connected With Us
hover these for magic

Get valuable tips, articles, and resources straight to your inbox. Every Tuesday.

  • http://www.pathsofdesign.com pathsofdesign

    First time seeing ui-router in action and I’m impressed! Thanks

  • http://dbfreebies.co Winter Stephane

    It looks really powerful and a good way to build modular app. Thanks for the tutorial.

  • Aaron Yang

    In “Nested Views”, code snippet is actually ‘partial-home.html’ instead of ‘index.html’

    • http://scotch.io/ Chris Sevilleja

      Good call. Fixed. Thanks.

  • Pingback: AngularJS Routing Using UI-Router | Angularjs +...

  • Pingback: Nova Tech Consulting Blog | AngularJS Routing Using UI-Router

  • Pingback: AngularJS Routing Using UI-Router | Nova Tech C...

  • migueljimenez

    Every time I see “x framework” I do not know if it is really a framework, a library or just a plugin; in the Javascript community those words are comming to be the same. Why is UI-Router a framework?

    • http://vkelman-blog.blogspot.com/ vkelman

      AngularJS is definitely a framework, UI-Router is just a small part of AngularJS ecosystem. Just Google for a comparison of AngularJS vs EmberJS vs Backbone…

      • Guest

        That was not my question, I know AngularJS, Backbone.js and Ember.js.

        • greg.benner

          -UI-Router is a plugin for the framework of Angular.
          -A framework is opinionated and more full featured, (Angular, Ember)
          -A library is a set of tools and un-opinionated (Backbone, jQuery, Underscore)

    • Vaseem Mohammed

      1. library is some helpful stuff which provides you with convenient methods to do which requires a lot of coding instead.(jQuery)
      2. Framework is something which will help you automate most of mundane tasks. It asks you to configure and it says i will take care of rest. (AngularJS)
      3. Plugin is something which is written for library or framework. library and framework are standalone, where as plugin requires either of this. (jquery-ui for jQuery and ui.router for angular)

      A plugin is called a framework as it depends on a framework and this plugin helps give more power to the exisitng framework.

      hope this helps

  • Michael

    In Nested Views “We’re going to add our buttons to index.html ” Aren’t they being added to partial-home.html even though you call that page page-home.html in the comment at the top of the code snippet? I’m new to this so I appreciate the tutorial.

    • http://scotch.io/ Chris Sevilleja

      Sorry that was a typo on my part. You’re right. That’s been updated.

  • Pingback: Ressource | Pearltrees

  • Logan Danger Black

    Hey, great article. I’m currently working on a new demo project that uses UI-Router to manage a page that is split into four views, and I was wondering if I could pick your brain on something.

    My project uses four views (We’ll call them 1,2,3,4) for three different states (A,B,C). The stateProvider makes it easy for me to define a starting point for each of these views, however I’m looking for a solution that allows more fine-grained control. For example, if a user clicks on a button in view 2, I want to be able to update the template/controller of view 4, while leaving the other three views alone. One possible way to do this is with sub-states (ie, “view1@stateA”, “[email protected]”) but there are a lot of possible combinations, so the list of states could get pretty large. At this time I only foresee the one view changing in this fashion, so sub-states isn’t TOO slippery of a slope in terms of scalability. Yet.

    My question is whether you’re aware of any other methodology which would allow these views to communicate with each other in such a fine-grained way?

    • http://scotch.io/ Chris Sevilleja

      That’s an interesting question. I think you’re on the right track with the sub-states. I don’t really know any other ways.

      There should be more experimentation with the whole multiple named views with relative and absolute names. You can define your application within children, in the parent, or many other ways. I think the solution lies somewhere in there.

      https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#view-names—relative-vs-absolute-names

      Sorry I couldn’t be more help.

  • EW

    super article , exactly the explanation I was looking for with nested views and non nested views

  • KD

    I try to apply the ng-leave and ng-enter in ui-view instead of ng-view. It didn’t work. Does anyhone know how to solve this problem?

  • Pingback: AngularJS Routing Using UI-Router | AngularJS -...

  • Pingback: Angular | Pearltrees

  • Maddy

    Hello, this is about removing # in the URLs [from your blog]. I tried to implement in my application. it works well as long as I dont reload the page with reload button of the browser [firefox in this case].

    Is it me doing something wrong or has it already been identified as an issue?

    Thanks!
    Maddy

  • Royce Lithgo

    Good intro article. I’m using UI Router in my current project and it’s really great. But the one thing I don’t have a solution for is nested states not being able to overwrite their parent’s template. It seems that nested states will always add on to their parent’s template. I want a nested state that can totally replace the parent (ie. i don’t want to include a in the parent template, but I want the nested state to use the same that the parent used.) Would be nice if there was some replaceParent option or something in the state definition.

  • http://vkelman-blog.blogspot.com/ vkelman

    Thanks, very clear and easy to read article. Sounds like a good way of structuring AngularJS application.

  • TypeMoreGooder

    Not impressed – but a lot of that has to do with the fact I spent 1/3 of the tutorial reading through typos – like completely misnamed files. Will have to look elsewhere for a better written tutorial/example.

  • thecodingwhale

    How can I handle the 404 page for the invalide URL? I already tried different approach but I cant work it well. Also, thanks again for the great tutorial Chris :)

  • Pingback: AngularJS Routing Using UI-Router | Angular.org...

  • http://www.helderlucas.com/ Helder Lucas

    Great Tutorial. Thanks :D

  • Bondifrench

    Great tutorial Chris, thx!

    One thing is we could have put the scotch and dog controllers, into a separate controllers.js to continue the seperation of concern, that you emphasized throughout thee tutorial.

    Question: when trying to make it html5/SEO friendly by adding $locationProvider.html5Mode(true).hashPrefix(!); it caused 2 issues:

    - the relative links in my partial-about.html page didn’t work, had to change them to absolute
    - the ui-sref=’#’ in index.html didn’t work anymore either, changed it to home
    Are there different ways to handle these issues?

  • Navin Kaushal

    I tried to make same example however my controller for inner links is only called once. I need to fetch some dynamic data. I put alert in that but did not work.

  • Pingback: AngularJS Links und Videos | Norbert Eder

  • OliverKK

    Beautiful tutorial! Thank you.

    How would be the routing done if the navigation changes after clicking on, let’s say ‘About’?
    Iam starting a project with a dynamic navigation bar. For example if i navigate to ‘Members’ dynamically a submenu appears after i clicked on it.

    So how would i solve this?

  • greg.benner

    I was wondering if there is an easy way with UI-router to say :
    ‘if home state is visible/open/on on click of trigger a close/remove/off”

  • http://john.mayonvolcanosoftware.com/ John Kevin Basco

    This is really a great tool. Thanks for this article! :)

  • Jeff Lee

    Any advice or best practices on how to write tests to check one’s implementation of Angular UI Router?

  • Arnab Sinha

    This is an excellent tutorial. Keep up the good work. The way it is presented is very logical and nice. The examples are also easy to follow as they are very simple.

  • Durgesh Singh

    well i am writing the code in webstorm and it create the local server each time when i run my angular route code page but it doesn’t work.. page is not displaying what i want. i installed the node.js and my all files and projects are in e drive.. is that somewhere i did wrong..? guide me please..

  • Pingback: AngularJS Routing Using UI-Router | need:brain

  • Pingback: AngularJS Multi-Step Form Using UI Router | Bee Scripts

  • Pingback: Mean | Pearltrees

  • Nirav Patel

    This helps me a lot. Thanks !

  • Pingback: Chromium + Raw Html (directly from a C# string) + Angular => Problems when attempting to use routing | Question and answer site for Developers – Msn4Free.com