Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 two 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?

like image 291
DavidA Avatar asked Jul 30 '14 22:07

DavidA


3 Answers

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>';
        }
    });
  }]
})
like image 141
Aman Mahajan Avatar answered Oct 22 '22 09:10

Aman Mahajan


You can also do the following :

$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') {
                    $timeout(function() {
                            $state.go('home.first');
                        }, 0);
                } else {
                    $timeout(function() {
                            $state.go('home.second');
                        }, 0);
                }
            }
        })
        .state('home.first', {
            url: '',
            templateUrl: 'first.html',
            controller: 'FirstController'
        })
        .state('home.second', {
            url: '',
            templateUrl: 'second.html',
            controller: 'SecondController'
        });
like image 9
malikba Avatar answered Oct 22 '22 09:10

malikba


I ended up making the home controller a sibling of first and second, rather than a parent, and then had the controller of home do a $state.go to first or second depending on the results of the resolve.

like image 3
DavidA Avatar answered Oct 22 '22 07:10

DavidA