4
votes

I am building the front-end app for a REST service, and most of the resources are located at long urls where most of the segments are dynamic based on records created in the app by users. Obviously I won't be able to know or create hardcoded routes for most of these records.

My question I suppose is how to handle urls like this with ui-router:

<semester>/<program>/<class>/enrollment

or

<semester>/myclasses/<class>/assignments

There is always at least one static, predictable segment in every resource url, and the segments are always in a predictable order.

Do I make abstract states for each segment in the url like:

$stateProvider.state(semester)  
    .state(program)  
    .state(class)  
    .state(assignments);

??

I've tried building routes that look like this:

param = {  
    name: "param",  
    url: "/:hue/:temp/param",  
    templateUrl: "http://localhost:81/route/tpl/param.tpl.html",  
    controller: "paramController"  
  };

but it ends up sending me back to the .otherwise() state when I link to the "param" state.

Thanks for any help, I'm a bit stumped.

3
I haven't used ui-router but I wonder if parameters need to be last. Ie, your route should be /param/:hue/:temp or /enrollment/:semester/:program/:class. To me it makes more sense that way since you're looking at an enrollment controller/action and passing in parameters of semester, program, and class - though that's a personal preference. - Mike Pugh
There's also a nice video of ui-router setup and an explanation of some of its internals @ egghead.io/lessons/angularjs-introduction-ui-router - Mike Pugh
OK I'll checkout those vids and see if they shed some light. I agree that technically it would make more sense to have the static portion in the beginning, but semantically and from a UX stand-point that solution would be counter-intuitive. Thanks for the tips! - Askdesigners
That's not really dynamic. Dynamic means you have no idea what the routes are because you have to load them from a database or something. UI-Router does simple route inheritance, such that if state a's route is "/a", and a.b's route is "/b", the full URL to b would be "/a/b". Since the parameterized structure of your routes is relatively well-defined, you should have no trouble modeling this with nested states. - Nate Abele
right. However my route segments will be coming from a database, and so are dynamic. In each there is at least one segment which is not dynamic which will allow ui-router to work. I've done a test and I have found a solution. See the answer here. - Askdesigners

3 Answers

1
votes

I had a similar problem and I quickly coded this:

.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('app', {
    url : "/app",
    abstract : true,
    templateUrl : "layout/navigation-drawer.tpl.html"

}).state('app.help', {
    url : "/help",
    views : {
        'menuContent' : {
            templateUrl : "layout/help.html"
        }
    }
}).state('app.settings', {
    url : "/settings",
    views : {
        'menuContent' : {
            templateUrl : "layout/settings.html"
        }
    }
}).state('app.rate-us', {
    url : "/rate-us",
    views : {
        'menuContent' : {
            templateUrl : "layout/rate-us.html"
        }
    }
}).state('app.projects', {
    url : "/projects",
    views : {
        'menuContent' : {
            templateUrl : "layout/projects.html",
            controller : 'ProjectsCtrl'
        }
    }
}).state('app.forms', {
    url : "/:project_name/forms",
    views : {
        'menuContent' : {
            templateUrl : "layout/forms.html",
            controller : 'FormsCtrl'
        }
    }
}).state('app.entries', {
    url : "/:project_name/:form_name/entries/:form_id",
    views : {
        'menuContent' : {
            templateUrl : "layout/entries.html",
            controller : 'EntriesCtrl'
        }
    }
});

which is working, "/:project_name/:form_name/entries/:form_id" will resolve to something like app/Mirko_test/University/entries/1

0
votes

Ok so I tested this out and it works in my case. It fails when the state is only a parameter, but it seems as long as each state has a non-parameterized bit, ui-router is able to parse down to children states. I haven't seen this case demonstrated or explained anywhere before. Most tutorials only cover simple hardcoded nested states and not parameterized ones.

It's not ideal, but it works.

I hope this helps someone else facing this issue. :)

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

.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function ( $stateProvider,   $urlRouterProvider, $locationProvider) {

  $urlRouterProvider.otherwise("/");
  $locationProvider.html5Mode(true);

  var semester = {
    name: "semester",
    abstract: true,
    url: "semester/:sem",
    templateUrl: "http://localhost:81/route/to/semtemplate.tpl.html",
    controller: "semesterController"
  },
  program = {
    name: "program",
    parent: sem,
    url: "program/:prg",
    templateUrl: "http://localhost:81/route/to/prgtemplate.tpl.html",
    controller: "programController"
  },
  classes = {
    name: "classes",
    parent: prg,
    url: "/classes",
    templateUrl: "http://localhost:81/route/to/clstemplate.tpl.html",
    controller: "classesController"
  };

  $stateProvider.state(sem)
    .state(prg)
    .state(classes);
}]);

app.controller('paraController', ['$scope', '$stateParams', '$state',function($scope, $state, $stateParams){
  console.log('paraController instantiated');
  $scope.sem = $stateParams.params.sem;
  $scope.prg = $stateParams.params.prg;
}]);

As this is a hierarchical REST api this pattern works perfectly, and when also taking advantage of scope inheritance from each controller it should be a good fit for my project. I haven't tested extremes of nested states, but it would be interesting to see how it behaves under even more parameterized states. The only limitation I have found is that each state needs to have a non-parameterized part as well. So /:sem fails but semester/:sem works fine.

It's not ideal as it makes URLs longer, but I haven't found a workable alternative.

0
votes

I know this question is old, but I had essentially the same question recently and found the official answer. Apparently, angular ui-router now supports the notion of URL Parameters in URL Routing, which allow you to specify parameters, along the lines of the following:

$stateProvider
    .state('contacts.detail', {
        url: "/contacts/:contactId",
        templateUrl: 'contacts.detail.html',
        controller: function ($stateParams) {
            // If we got here from a url of /contacts/42
            expect($stateParams).toBe({contactId: 42});
        }
    })

For more info, go here: https://github.com/angular-ui/ui-router/wiki/URL-Routing#url-parameters