javascriptangularjsangular-ui-routernested-views

Parent controller instantiated each time a child view is called


I am using ui-router and I have a configuration in which I am using a parent view which has a controller and child view which also have their own controllers. Each time I navigate to one of the child views, the parent controller is instantiated again and therefore performs unnecessary requests to the server. I want to be able to navigate between the child states and reuse the variables that were resolved by the parent controller.

How can I prevent the parent controller from being instantiated each time?

This is my routing config:

$stateProvider
    .state('researchLayoutEditor', {
        url: '/research/:researchId/layoutEditor/:orderInGroup',
        controller: 'layoutEditorController',
        controllerAs: 'layoutEditorCtrl',
        templateUrl: 'app/researchManagement/researchLayoutEditor/layoutEditor.html',
        redirectTo: 'researchLayoutEditor.slide',
        params: {
            group: 'A',
            orderInGroup: '0'
        },
        resolve: {
            researchLayout: function (researchesService, $stateParams) {
                return researchesService.getResearchLayout($stateParams.researchId, false);
            },
            research: function (researchesService, $stateParams) {
                return researchesService.getResearch($stateParams.researchId);
            }
        }
    }).state('researchLayoutEditor.slide', {
        url: '/textual',
        templateUrl: 'app/researchManagement/researchLayoutEditor/textSlide.html',
        controller: 'textSlideController',
        controllerAs: 'txtSlide'
    }).state('researchLayoutEditor.movie', {
        url: '/video',
        templateUrl: 'app/researchManagement/researchLayoutEditor/movieSlide.html',
        controller: 'movieSlideController',
        controllerAs: 'movieSlide',
        resolve: {
            movieCategories: function (utilsService) {
                return utilsService.getVideoCategories();
            }
        }
    }).state('researchLayoutEditor.memory', {
        url: '/memory',
        templateUrl: 'app/researchManagement/researchLayoutEditor/memorySlide.html',
        controller: 'memorySlideController',
        controllerAs: 'memorySlide'
    }).state('researchLayoutEditor.question', {
        url: '/question',
        templateUrl: 'app/researchManagement/researchLayoutEditor/questionSlide.html',
        controller: 'questionSlideController',
        controllerAs: 'questionSlide'
    });

And this is the HTML:

<div id="mainContent">
    <!-- our nested state views will be injected here -->
    <div ui-view class="inner-content"></div>
</div>

Solution

  • Well, after trying the most helpful way of debugging by elimination I found the problem which was the way I built the URL. IN my parent state, I had the URL defined like this:

    url: '/research/:researchId/layoutEditor/:orderInGroup',
    

    when the orderInGroup parameter changed on each click on the child state. So the final URL looked like this for example:

    .../#/research/37/layoutEditor/1/video

    Apparently, after changing the location of the "orderInGroup" parameter and putting it to the end of the URL

    .../#/research/37/layoutEditor/video/1

    and moving the

                    params: {
                        group: 'A',
                        orderInGroup: '0'
                    }
    

    object to the child states as well, the issue was resolved. So the URL configuration that finally worked looked like this (I moved the /:orderInGroup to child state):

    $stateProvider
                .state('researchLayoutEditor', {
                    url: '/research/:researchId/layoutEditor',
                    controller: 'layoutEditorController',
                    controllerAs: 'layoutEditorCtrl',
                    templateUrl: 'app/researchManagement/researchLayoutEditor/layoutEditor.html',
                    redirectTo: 'researchLayoutEditor.slide'
                })
                .state('researchLayoutEditor.movie', {
                    url: '/video/:orderInGroup',
                    templateUrl: 'app/researchManagement/researchLayoutEditor/movieSlide.html',
                    controller: 'movieSlideController',
                    controllerAs: 'movieSlide',
                    params: {
                        group: 'A',
                        orderInGroup: '0'
                    }
                })
                .state('researchLayoutEditor.slide', {
                    url: '/textual/:orderInGroup',
                    templateUrl: 'app/researchManagement/researchLayoutEditor/textSlide.html',
                    controller: 'textSlideController',
                    controllerAs: 'txtSlide',
                    params: {
                        group: 'A',
                        orderInGroup: '0'
                    }
                });