Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage state with the ui-router with multiple modules

I have an app page with 3 columns. The middle column is the main activity and is always displayed. The two side columns are widget lists, that have their own controller and states, and can be either hidden or unhidden, and have multiple views within them as well. Ideally, I'd imagine url routes like the following:

/app - main activity is shown, both panels hidden

/app/1234 - main activity is shown, but shows info for 1234 entity

/app/1234/leftpanel - main activity is shown with 1234 entity, and leftpanel is open

/app/1234/leftpanel/list - main activity is shown with 1234 entity, and leftpanel is showing the list view

/app/leftpanel/list - main activity is showing default state, leftpanel is still showing the list

Is this possible to setup with ui-router? I've seen this example:

https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions

which shows how to use the $stateProvider between multiple modules, but I'm still not seeing how to make this scenario work-

like image 542
chrismarx Avatar asked Aug 02 '13 14:08

chrismarx


1 Answers

I did resolve the issue. I also posted about this on the angular-ui github, and their response was basically, "well, that case isn't really what the router has been designed for, so if you want "fancier" state management, put the data in parameters and look at them yourself and implement whatever logic you need". I kinda felt that this was what the ui-router was designed for, so I extended it a bit (no source code changes) to accomplish this. The solution is a combination of abstract states, a fake "off" state, parameters in the router urls, and extending the $urlRouterProvider service.

First extend the $urlRouterProvider:

urlRouterProvider.when(/^((?!leftpanel).)*$/, ['$state', '$location', function ($state, $location) {
 //we've got just /app or /app/3434, nothing that contains /leftpanel, so turn off    
 $state.transitionTo("off");
   }]);

Then add that "off" state:

$stateProvider.state('off',{
 //url: //there is no url
 views:{
   container:{
     template: 'blank',
     controller:['$scope', '$stateParams', function($scope, $stateParams){
       console.log("off yay"); //just for sanity, not necessary
     }]
   }
 }});

Then setup the rest of the app routing:

appModule.constant('LEFT_PANEL_STATES', function() {

var leftPanelRoot = { 
  name: 'root.leftpanel',  //mandatory
  template: '',
  url: "/app/:primaryId/leftpanel",
  views:{
      'container@': {
          templateUrl: "partials/leftpanel_container_partial.html",
          controller:"LeftPanelRootCtrl",
          resolve: {
            //etc
          }
      }
  },
   "abstract":true //makes this view only viewable from one of its child states
};

var leftPanelItemsList = {
  name: 'root.leftpanel.itemslist',  //mandatory
  parent: leftPanelRoot,  //mandatory
  url: "/items-list",
  views:{
      '[email protected]': {
          templateUrl: "partials/leftpanel_items_list.html",
          controller:"LeftPanelItemsListCtrl",
          resolve: {
           //etc
          }
      }
  }};


 var leftPanelListDetail = {
name:"root.leftpanel.itemslist.detail",
parent:leftPanelItemsList,
url:"/:id/detail",
views:{
  "detail":{
    templateUrl:"partials/leftpanel_item_detail.html",
    controller:"LeftPanelItemListDetailCtrl"
  }
}};

  var leftPanelExtendedDetailList = {
name:"root.leftpanel.itemslist.extendedlist",
parent:leftPanelItemsList,
url:"/:id/extendedDetail/list", 
views:{
  "extendeddetaillist":{
    templateUrl:"partials/leftpanel_extended_detail_list.html",
    controller:"LeftPanelExtendedDetailListCtrl"
  }
}};
like image 103
chrismarx Avatar answered Nov 08 '22 16:11

chrismarx