ui-router default child state not working

2020-03-23 18:06发布

问题:

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>

回答1:

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



回答2:

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>'
            }
        }
    });

}