DavidA DavidA - 2 months ago 7
AngularJS Question

Angular ui-router to accomplish a conditional view

I am asking a similar question to this question: UI Router conditional ui views?, but my situation is a little more complex and I cannot seem to get the provided answer to work.

Basically, I have a url that can be rendered to very different ways, depending on the type of entity that the url points to.

Here is what I am currently trying

$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$state.transitionTo('home.first');
} else {
$state.transitionTo('home.second');
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});


I set up a Resolve to fetch the actual entity from a restful service.
Every thing seems to be working until I actually get to the transitionTo based on the type.

The transition seems to work, except the resolve re-fires and the getEntity fails because the id is null.

I've tried to send the id to the transitionTo calls, but then it still tries to do a second resolve, meaning the entity is fetched from the rest service twice.

What seems to be happening is that in the onEnter handler, the state hasn't actually changed yet, so when the transition happens, it thinks it is transitioning to a whole new state rather than to a child state. This is further evidenced because when I remove the entity. from the state name in the transitionTo, it believes the current state is root, rather than home. This also prevents me from using 'go' instead of transitionTo.

Any ideas?

Answer

The templateUrl can be a function as well so you check the type and return a different view and define the controller in the view rather than as part of the state configuration. You cannot inject parameters to templateUrl so you might have to use templateProvider.

$stateProvider.state('home', {
  templateProvider: ['$stateParams', 'restService' , function ($stateParams, restService) {
    restService.getEntity($stateParams.id).then(function(entity) {
        if (entity.Type == 'first') {
              return '<div ng-include="first.html"></div>;
        } else {
              return '<div ng-include="second.html"></div>';
        }
    });
  }]
})