Search code examples
angularjsangular-uiangular-ui-router

How to handle long dynamic urls with angular ui-router?


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.


Solution

  • 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.