Search code examples
angularjsangular-ui-routerangular-uistate

UI-Router parent controller doesn't initiate


I'm using AngularJs UI-Router for my app, but I'm with a problem where the parent's controller isn't initiated.

This is my state structure:

.state('main', {
    abstract: true,
    controller: 'MainController',
    controllerAs: 'vm',
    resolve: {
        config: function($timeout){
            return $timeout(function() {
                return console.log('loaded')
            }, 1000);
        }
    }
})
.state('home', {
    parent: 'main',
    url: '/Home',
    views: {
        'content@': {
            templateUrl: 'view/home.html'
        }
    }
})
.state('contact', {
    parent: 'main',
    url: '/Contact',
    views: {
        'content@': {
            templateUrl: 'view/contact.html',
        }
    }
})

The template home.html and contact.html are displaying on the view just fine. But inside the MainController I have just a console.log but it doesn't appear on the console.

If I make some changes, I can make it work. This is the working example:

.state('main', {
    abstract: true,
    views: {
        'main': {
            template: '<div ui-view="content"></div>',
            controller: 'MainController',
            controllerAs: 'vm'
        }
    }
[...code...]

.state('home', {
    parent: 'main',
    url: '/Home',
    views: {
        'content': {
[...code...]

This way, everything works as expected, The view appear and the console from the controller also appear.

But it doesn't seem "right" because I need to create a template just to hold the child states.

Is there a way to make it work with the first option?


Solution

  • Well, to answer:

    ... Is there a way to make it work with the first option?

    Have to say: NO. The point is:

    Scope Inheritance by View Hierarchy Only

    Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

    It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

    So, what happened is - the child state views: {} definition:

    .state('contact', {
        parent: 'main',    
        views: {
            'content@': {
        ...
    

    ... forced child to skip parent view. Not parent state. It skips a parent view. There is no parent view, from which it could inherit the $scope.

    The view of a child state 'contact', is injected directly into root (index.html) ui-view="content", it will not trigger parent view...

    So, use the second approach, which is absolutely correct, to achieve what is exepected

    Check also these for farther details and working examples: