8

I have states defined as below in my angularjs app using angular ui router state provider. And, I would like to define multiple states with the same configuration ie. with the same template and controller.

$stateProvider
        .state('parent', {
            templateUrl: 'parent.html',
            abstract: true,
            parent: 'apm'
        })
        .state('parent.list', {
            abstract: true,
            url: '/list',
            templateUrl: 'list.html',
            controller: 'ListCtrl'
        })

        .state('parent.list.closed', {
        url: '/q',
        templateUrl: 'closed.html'
        })

        .state('parent.list.details', {   // would like to have same template, controller on different state parent.details without list
            url: '/:id/:name',
            abstract: true,
            templateUrl: 'details.html',
            controller: 'DetailsCtrl',
            resolve: {
                .....
                .....
            }
        })
        .state('parent.list.details.data', { // would like to have same template, controller on different state parent.details.data without list
          url: '/details',
          views : {
            'view1' : {
              templateUrl : 'view1.html'
            },
            'view2' : {
              templateUrl : 'view2.html',
              controller : 'View2Ctrl'
            },
            'view3' : {
              templateUrl : 'view3.html'
            },
            'view4' : {
              templateUrl : 'view4.html'
            }
          }
        })

Is it possible to do something like

.state(['parent.list.details', 'parent.details'], {   
            url: '/:id/:name',
            abstract: true,
            templateUrl: 'details.html',
            controller: 'DetailsCtrl',
            resolve: {
                .....
                .....
            }
        })

Any help or suggestions?

1
  • why don't you extract the common options to a plain javascript variable or even an angular constant? I guess you're doing to dry up sake, right? Commented Mar 13, 2015 at 23:28

2 Answers 2

7

Each state needs to be defined in it's own .state() method. You will run into multiple problems trying to do it the way you listed above. Most importantly would be the url.

You can simply do this:

    .state('parent.list', {   
        url: '/list',
        abstract: true,
        templateUrl: 'details.html',
        controller: 'DetailsCtrl',
        resolve: {
            .....
            .....
        }
    .state('parent.list.details', {   
        url: '/:id/:name',
        abstract: true,
        templateUrl: 'details.html',
        controller: 'DetailsCtrl',
        resolve: {
            .....
            .....
        }
    })

While the code is not condensed or efficient in the sense you have to declare the controller and partial used on each state, it is necessary because each state needs its own .state() method

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the quick response. My only concern was to repeat bunch of lines of code for the new states I want.
Yeah like I was saying it isn't the most efficient but because uiRouter requires the .state() method to be declared for each state I don't see a way around it. Here is a quote direct from uiRouter's wiki _ "States often have things in common, and the primary way of factoring out these commonalities in this model is via the state hierarchy, i.e. parent/child states aka nested states."
if same controller is bind with different states, then the functions that execute on bind like: getting list from server will be called again and again, that is what I am in problem now. What could be a possible solution?
3

I wanted the same and made it like this:

//add a new Function to the object $stateProvider
               $stateProvider.states = (statesArr, obj) => {

                   for (var i in statesArr) {
                       var state = statesArr[i];

                       $stateProvider.state(state, obj);
                   }

                   return $stateProvider;
               };


//use the new function
               $stateProvider

               .states(["main", "main.test"], {
                   url: '/main',
                   templateUrl: 'modules/ViewContainer.html',
                   controllerAs: 'currentCtrl',
                   controller: 'MainCtrl'
               })

1 Comment

work great, i had to clone the state object to make it work with $state.go('^.mystate'); example with underscore : $stateProvider.state(state, _.clone(obj));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.