Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ui-router default child state not working

I'm testing UI-Router nested state, but I'm not able to set default state in parent/child scenario, please help.

libraries:

  • angular 1.3.15
  • ui router: 0.2.15

navigation path:

/ - home
/settings - parent state/page
/settings.default - child 1
/settings.mail - child 2
/settings.phone - child 3

expected behavior:

when navigating to /settings, the default child 'general' state/page should be triggered/loaded

actual behavior:

If I set 'settings' state 'abstrat: true', there will be error:

Error: Cannot transition to abstract state 'settings'
    at Object.transitionTo (angular-ui-router.js:3143)
    at Object.go (angular-ui-router.js:3068)
    at angular-ui-router.js:4181
    at angular.js:16299
    at completeOutstandingRequest (angular.js:4924)
    at angular.js:5312

If I remove 'abstrat: true', there's no error, but when i navigate to /settings, default child state/page - general state not triggered, settings.html displayed but not loaded

app.js:

angular.module('test',['ui.router','sails.io'])     //config routing
.config(['$stateProvider','$urlRouterProvider','$locationProvider',
        function($stateProvider,$urlRouterProvider,$locationProvider) {

  $urlRouterProvider.otherwise('/');    
  $locationProvider.html5Mode(true);

  $stateProvider
    .state('home', {
        url: '/',
        templateUrl: 'views/index.html',
        controller: 'IndexController'
    })
    .state('settings', {
        abstract: true,
        url: '/settings',
        templateUrl: 'views/settings.html',
        controller: 'SettingsController'
    })
    .state('settings.general', {
        url: '',
        templateUrl: 'views/settings/general.html',
        controller: 'SettingsController'
    })
    .state('settings.mail', {
        url: '/mail',
        templateUrl: 'views/settings/mail.html',
        controller: 'SettingsController'
    })
    .state('settings.phone', {
        url: '/phone',
        templateUrl: 'views/settings/phone.html',
        controller: 'SettingsController'
    });
}]);

views/settings.html

<div class="container">
  <div class="row">
    <div class="col-md-3">
      <ul class="list-group">
        <li class="list-group-item"><a ui-sref=".general">General</a></li>
        <li class="list-group-item"><a ui-sref=".phone">Phone</a></li>
        <li class="list-group-item"><a ui-sref=".mail">Mail</a></li>
      </ul>
    </div>
    <div class="col-md-9">
      <div ui-view></div>
    </div>
  </div>
</div>
like image 306
jerry Avatar asked May 20 '15 10:05

jerry


2 Answers

There is a working plunker

This would work, but just with url navigation, i.e. href:

  <a href="/settings"> // will work

But this will not - we cannot go to abstract state:

  <a ui-sref="settings">settings</a>

But based on this Q & A:

Redirect a state to default substate with UI-Router in AngularJS

We can remove abstract and create default state handling like this. There is updated plunker

// redirection engine
app.run(['$rootScope', '$state', function($rootScope, $state) {

    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params)
      }
    });
}]);

The parent stat adjustment:

.state('settings', {
    //abstract: true,
    redirectTo: 'settings.general',
    url: '/settings',
    ...

Check it here

like image 128
Radim Köhler Avatar answered Oct 10 '22 07:10

Radim Köhler


I realize this is an older question, but I thought I'd add something in case it helps someone else:

Although you may not want to add a plugin to solve this problem, you should check out UI-Router-Extras

There is a feature included there called "Deept State Redirect". This allows any state to save the most recently activated substate so that when you transition away, then back, the same substate (child state) will be active.

The part that would help your problem is being able to define a default child state. You do that by adding the "dsr" parameter and setting the "default" to whatever your child state is.

function myRouterConfig ($stateProvider, $urlRouterProvider) {
 $stateProvider
    .state('parentState', {
        //Not in this file          
        parent: 'index', 
        sticky: true,
        //ui-router-extras deepStateRedirect option
        dsr: {  
            default: 'parentState.defaultChild'
        },
        url: '/parentState',
        views: {
            'main@index': {
                template: '<my-parentStateComponent>'
            }
        }           
    })
    .state('parentState.defaultChild', {
        url: '/defaultChild',
        views: {
            'child@parentState': {
                template: '<my-defaultChildComponent>'
            }
        }
    });

}

like image 27
dmungin Avatar answered Oct 10 '22 06:10

dmungin