Setting up states from a json file in angularjs applications


Imagine a this simple angularjs application using angular-ui-router:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Example</title>
    <script src="bower_components/angular/angular.js"></script>
    <script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="js/app.js"></script>

</head>
<body ng-app="App" ng-controller="MainController">

<div ui-view></div>
</body>
</html>

angular.module('App', ['ui.router'])

    .config(function ($stateProvider, $urlRouterProvider, routerProvider) {
        $stateProvider
            .state('home', {
                url: '/home',
                templateUrl: 'templates/home.html'
            });

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

    .controller('MainController', function ($scope, router) {
        $scope.reload = function() {
            router.setUpRoutes();
        };
    })
;

We’ve defined only one state called “home”. If we need more states we just add more within config() function. In this post we’re going to try to add more states from a json file instead of hardcode the states within the code.

Let’s create our json file with the states definitions:

{
    "xxx": {
        "url": "/xxx",
        "templateUrl": "templates/xxx.html"
    },

    "yyy": {
        "url": "/yyy",
        "templateUrl": "templates/yyy.html"
    },

    "zzz": {
        "url": "/zzz",
        "templateUrl": "templates/zzz.html"
    }
}

Now our application looks like this:

angular.module('App', ['ui.router', 'Routing'])

    .config(function ($stateProvider, $urlRouterProvider, routerProvider) {
        $stateProvider
            .state('home', {
                url: '/home',
                templateUrl: 'templates/home.html'
            });

        $urlRouterProvider.otherwise('/home');

        routerProvider.setCollectionUrl('js/routeCollection.json');
    })

    .controller('MainController', function ($scope, router) {
        $scope.reload = function() {
            router.setUpRoutes();
        };
    })
;

As we can see now we’re using ‘Routing’

angular.module('Routing', ['ui.router'])
    .provider('router', function ($stateProvider) {

        var urlCollection;

        this.$get = function ($http, $state) {
            return {
                setUpRoutes: function () {
                    $http.get(urlCollection).success(function (collection) {
                        for (var routeName in collection) {
                            if (!$state.get(routeName)) {
                                $stateProvider.state(routeName, collection[routeName]);
                            }
                        }
                    });
                }
            }
        };

        this.setCollectionUrl = function (url) {
            urlCollection = url;
        }
    })

    .run(function (router) {
        router.setUpRoutes();
    });

‘Routing’ provides us a provider called ‘router’ that fetch the json file and build the states.

That’s a proof of concept.
There’s a couple of problems (please tell me if you know how to solve them):

  • As far as we’re loading states from a http connection, angular application don’t have all the states when it starts, so we need to create at least the first state with the “old style”
  • We can reload states with the application running. We also can add new states, but we cannot modify the existing ones.

you can see the one example project within my github account.

16 thoughts on “Setting up states from a json file in angularjs applications

    1. The idea behind this experiment is reload routes dynamically. Imagine a phonegap/cordova application. If add one route I need to redeploy the app. If routes can be loaded from a remote url, I can send a websocket/pushNotification and reload the routes. Another purpose is to write routes in a clean template. I’ve got a PHP/Symfony background and that’s the way Sf does.

      1. Interesting. I haven’t done any phonegap apps, so I might be missing something… but, if you add new routes, wouldn’t you also be adding views/controllers/models to correspond to the new route (essentially, a new feature)? Wouldn’t this require you to redeploy the app anyway?

      2. it depends. For example views can be set with templateUrl (and the url can be a remote server url). When we work with phonegap/cordova applications we must take into account that resources are inside our device. One simple change within our main index.html file means redeploy the application. And redeploy means that we cannot assert if user upgrades the application or not. Every change we do without redeploy may be good.

        Anyway this post is just an experiment. An experiment playing in the edge of cordova application. Something like ¿Is is possible to that? Let’s try it

  1. great solution.

    Needed something too, where you could only see their routers after logged

    This solution could be used in production?

    I do not understand how to use ui router Resolve to this case

    1. Be careful “hide” routes to unlogged users may not be a good solution. It sounds like “security through obscurity”.

      I’m not using it in production. It’s just a prof of concepts.

  2. I’m trying solution but loading the routes from the db. However it’s not working for deep linking. For example (using your example routes) I can go to the url “/home” then navigate to “/xxx”. This works but when I reload the page I am redirected back to “/home”. Is it the same for you?

    I’m starting to thing the right way may be to write your own route service to use instead of ui router.

    1. Yes I don’t know how to solve it yet. That’s because initial routes are created within config() and extra routes are loading in run().

    1. I don’t understand when you say “links from json file can’t be generated using ui-sref directive”. Do you have an example?

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.