Using The UI-Router To Navigate In Ionic Framework

Being that Ionic Framework relies heavily on the UI-Router for navigation, I thought I would do a write-up on how to properly use it.

We use the UI-Router to navigate between view states in our application.  By view states, I mean screens composed as template files.  If you’re looking for information on navigating in Ionic 2, visit my other post on the subject as it doesn’t use the UI-Router like Ionic Framework 1 does.

Let’s start by creating a new Android and iOS Ionic project:

Note that if you’re not using a Mac, you cannot add or build for iOS.

The UI-Router operates on application states, where each state might represent a new screen in your application.

Take the following code:

In the above code we are going to pay attention to the .config() method.  There are three states which represent three screens in our app.  We have the following screens:

  • A login screen
  • A screen for showing all users.  This is the default screen when the application loads
  • A screen for showing a specific user

Now lets break down what each part of the state represents.


Object Key Description
url The URL route that can be accessed via href properties
templateUrl The path to the view template HTML file
controller The controller to be used in this view

Take the following chunk of code:

The template we will use is found in www/templates/user.html in our project.  Notice that in our URL we have :userId.  This represents a parameter that will be passed into our controller.

So how might all this look from a UI perspective?  Let’s start with our index.html file.

You’ll notice the highlighted line.  This is where the template will be injected via your UI-Router.  So it is now time to create our templates:

The above code is suitable for our www/templates/users.html file.  You’ll notice clicking on a list item will pass the user id as one of the parameters.

All your other templates will follow a similar design.

If you’d like to read more on the topic of application states and the UI-Router, you can view the official GitHub documentation.

Nic Raboy

Nic is a skilled application developer who has released several native and hybrid mobile applications to iTunes and Google Play. He writes about his development experiences related to making web and mobile app development easier to understand and has experience in Android, Node.js, Apache Cordova, Java, NoSQL, SQL, GoLang, NativeScript, and Unity3D.

  • Stephen Kuehl

    How would you go about linking an item in a playlist to a unique page?

    • Can you give me an example of what you’re trying to accomplish?

      Regards,

      • Stephen Kuehl

        Lets say a user wants to click on item in the list. How do I link that item to a new view based on the order in which the item is listed (:Playlist.Id)?

        • Well, you can pass as many $stateParams as you want. In this tutorial, I showed how to make use of $stateParams, but you can always get the index of your clicked list element and pass that as well.

          I can’t imagine having a unique page per element. You’d only want to change the data on the page.

          Does that answer your question?

  • Yanupla

    How i can make routing using this example: http://learn.ionicframework.com/formulas/backend-data/

    This example have an external JSON file, i’m ok with that, the problem that i have is how implement routing, how i can add a detail page of my JSON file element that show it when i click an item of my list, accorded to the item number in ng-repeat.

    • I don’t think I understand what you’re talking about.

      If you’re just looking to have a a list that directs to a detail page with data populated from JSON, this tutorial demonstrates that.

      Your list would have item ids that you would pass to the detail state. You would pick up that id using $stateParams and get the data you need based from it.

      Regards,

      • Guest

        I Have this From ionic tabs template (Resuming)
        1) app.js
        .state(‘tab.friends’, {
        url: ‘/friends’,
        views: {
        ‘tab-friends’: {
        templateUrl: ‘templates/tab-friends.html’,
        controller: ‘FriendsCtrl’
        }
        }
        })
        .state(‘tab.friend-detail’, {
        url: ‘/friend/:friendId’,
        views: {
        ‘tab-friends’: {
        templateUrl: ‘templates/friend-detail.html’,
        controller: ‘FriendDetailCtrl’
        }
        }
        })

        2) I have This in controller.js
        .controller(‘FriendsCtrl’, function($scope, Friends) {
        $scope.friends = Friends.all();
        })
        .controller(‘FriendDetailCtrl’, function($scope, $stateParams, Friends){
        $scope.friend = Friends.get($stateParams.friendId);
        });

        3) Have This is services.js
        .factory(‘Friends’, function($http) {
        var friends = $http.get(“json/equipos.json”).then(function(response){
        friends = response.data;
        console.log(friends);
        });
        return {
        all: function(){
        return friends;
        },
        get: function(friendId) {
        // Simple index lookup
        return friends[friendId];
        }
        }
        });

        4) Have this in json/equipos.json file
        [ {
        “id”: 0,
        “name”:”Olimpia Club de Football”,
        “shortname”:”olimpia_cf”,
        “reknown”:”Lorem ipsum dolor sit amet”,
        “bio”:”Lorem ipsum dolor sit amet”
        } ]

        I can see the JSON File using console.log, but It doesn’t show anything in my tabs-friends.html template.

      • Yanupla

        I’ll try to resume, this is what a have from IONIC Tabs Template:

        1) App.js
        .state(‘tab.friends’, {
        url: ‘/friends’,
        views: {
        ‘tab-friends’: {
        templateUrl: ‘templates/tab-friends.html’,
        controller: ‘FriendsCtrl’
        }
        }
        })
        .state(‘tab.friend-detail’, {
        url: ‘/friends/:friendId’,
        views: {
        ‘tab-friends’: {
        templateUrl: ‘templates/friend-detail.html’,
        controller: ‘FriendDetailCtrl’
        }
        }
        })

        2) Controllers.js
        .controller(‘FriendsCtrl’, function($scope, Friends) {
        $scope.friends = Friends.all();
        })
        .controller(‘FriendDetailCtrl’, function($scope, $stateParams, Friends) {$scope.friend = Friends.get($stateParams.friendId);
        })

        3) Services.js

        .factory(‘Friends’, function($http) {
        var friends = [];
        return {
        all: function(){
        return $http.get(“http://yanupla.com/apps/ligajaguares/equipos.json”).then(function(response){
        friends = response.data;
        console.log(friends);
        return friends;
        });
        },
        get: function(friendId) {
        for (var i = 0; i < friends.length; i++) {
        if (friends[i].id === parseInt(friendId)) {
        return friends[i];
        }
        }
        return null;
        }
        }
        });

        Using console.log i can see the JSON Object, but in my tabs-friends.html template doesn’t show anything

        4) tabs-friends.html

        • I’m not going to look at your code unless you either format it with pre and code tags with proper indentation or post it on GitHub. It is far too troublesome to clean up raw code posted in the comments section.

          Regards,

  • rachit handa

    hi nic, is it possible that we can give state to the each slide of an ionic slidebox. actually in my application, when from slide 3 i go into a different view, and on the click of ionic back button i want to return to slide 3 of the slide box. thanks

    • I’m not sure if there is a way to capture the current slide. The official Ionic documentation didn’t say.

      You may want to ask in the forums how to do this, if it is even possible of course.

      Regards,

    • David Zhu

      Did you manage to find a solution? I’m having the same trouble.

  • Dane Hollenbach

    I am having a strange issue. Which is as follows. On android > 4.4 and ios my app routes properly but on android 4.3, 4.2.1 and 4.1.2 the view just does not load. The main view works and is functional but I cannot get the other views to load. It’s almost like the buttons/tabs does nothing. Any ideas?

    • What do your logs say?

      • Dane Hollenbach

        That is just it. No error to report. Is this maybe a bug ionic?

        It is specific to the Android versions I mentioned. Any ideas?

        • Yea you might want to create them a ticket for this if there are no logs.

  • Valerio Radice

    I Nic i try to create an app with router UI and i’m following your video example of ToDoList but when i try to start app in ndroid simulator in console i found this error:

    Uncaught Error: [$injector:modulerr] Failed to instantiate module starter due to:
    Error: State ‘service” is already defined
    at registerState (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:40095:44)
    at $StateProvider.state (file://……1)

    What can i do for fix it?

    here ( http://pastebin.com/VWijK80n ) my code
    thank you very much

    • Could it be because you have a space in your controller name?:

      appTpl.controller(“service Controller”, function($scope){});

      Regards,

      • Valerio Radice

        thank you nic, i try but now i dosen’t have any error but page is always blank 🙁
        can you create a simple zip with 3 section (home, one, two) of a basic example?

        • If the page is blank then your logic is off or you have an error.

          I don’t provide zip files, but I’d be happy to keep giving you tips to correct your problems.

          Regards,

          • Valerio Radice

            i create a new git project, can u check it please?
            https://github.com/valix85/ionic-router-ui

          • You call the following:

            $urlRouterProvider.otherwise(‘/start’);

            However, you have no URL route for “/start”. You probably want this instead:

            $urlRouterProvider.otherwise(‘/’);

            Regards,

          • Kartik

            i have a starting page called index.html where I sign in and it takes me to dashboard.html. Here, I have ionic tabs below and when i click a tab it should take me to various screens using $stateProvider, which is not happening. I can share screen shots if you need or share the code. Please reply.

          • If it isn’t working, what do your error logs say?

            Regards,

          • Kartik

            Ok sorry that was resolved… I have another question.
            How do enter time in timepicker and add it to a textbox. Also I am not able to show a result variable in a textbox but getting the result in an alert. I tried ng-bind, ng-model and controllers.

          • I believe you’re a first time offender of this so I can’t blame you for not knowing, but I don’t answer questions that are off topic to the post. If you want to request an article, you can see here:

            https://www.thepolyglotdeveloper.com/2015/07/what-programming-tutorials-do-you-want-to-see/

            If you just have a question and would rather not see a post be made, find me on Twitter (@nraboy).

            Regards,

          • Kartik

            oh, I’m extremely sorry.. I understand that….I’ll catch you on twitter.

          • No worries, can’t blame you for not knowing 🙂

  • angelxmoreno

    Do templates need to say the controller they are bound to? Or does ui-router already do that in the config? I ask because your users.html template has ng-controller=”UserController” in it.

    • Thanks for pointing that out! I had it in my template in error. It has been removed from the snippet 🙂

      • angelxmoreno

        awesome. I’m curious, did you start using ui-router when you started using Angular? I am new to ui-router but not Angular. I feel like the multiple view architecture replaces the need for (most) directives. For example, in a traditional Mail App, I would make a directive for showing the folders, another for showing list of email etc. Each directive would have its own controller managing the changes to their view templates. Am I crazy to say that I would no longer have to do that with ui-router?

        • I’m not sure I follow.

          The AngularJS ui router will allow you to use templating / partials to keep a single page design. Instead of having a mess of includes and other code scattered in each page, you can have a parent template and have each view be its own partial.

          When I code, I have a controller for a group of similar views. For example I’ll make an AngularJS controller for account related operations. Typically a list, insert, update, and delete set of views will go into that controller.

          You can nest views making it so you have for example an email list on one side and a single email content on the other.

          Does that make sense?

  • Shruti Rathi

    I have the requirement.. where I have one homepage and other pages will have same UI.. I was thinking to create a seperate template for other screens which will have common header and render all screens in it. Is it possible to do this? can you please guide how to do this?

  • Miguel Alves

    Hey Nic Thanks so much for this small tut was awesome and works great, really helped a lot

  • Nizar Bsb

    Hi nic, very good stuff, thank you very much!

  • Chems

    Hi Nic, is there a way to pass the entire JSON object (user) instead of a single item (user.id). Thx for the great tuto!

    • You can pass an object using ui-sref, but I wouldn’t pass your whole object. You should only pass ids around and do a lookup on the next screen.

  • Che Carlitos

    Okay Nic, thanks for help, but, can i pass other data to single page with this method? Because i’ve a lot of data and i need pass it into single page by “User ID”

    • If you need to pass around a lot of data I suggest to query for it on the next page. I don’t suggest passing more than the ids around.

  • Mayank Sheth

    Hey Nic, thank you for amazing post. It was really helpful. I have one question regarding how views are loaded. Is there a way to lazy load the views when view is requested by application? I have 10-15 views in my application configured by various states in app.js. But I see all the views are loaded when application is launched as per browser’s developer tool. For example: In your example, user.html and login.html both will load even if user hasn’t requested login.html (yet!). I am looking for some kind of lazy loading of views. Please advise.

  • Mojo Jojo

    hey thanks for this simple tutorial. I have a question

    some route states contains views property for exaple
    .state(‘users’, function(){
    url: ‘/’,
    views: {
    ‘map-tab’:{
    templateUrl:’templates/map.html’,
    controller:’MapCtrl’
    }
    }

    what is the purpose of views?

  • Tun Dolralim

    hi..im new to angular and ionic. In angular…if u want to call a controller…u use ng-controller…but in ionic…how we can call(link)

    the controller? thanks in advance