ocombe / ocLazyLoad

Lazy load modules & components in AngularJS
https://oclazyload.readme.io
MIT License
2.63k stars 510 forks source link

ocLazyLoad not loading ui-route nested child route controller #317

Open ghost opened 8 years ago

ghost commented 8 years ago

I have a nested child route that does not load its controller. The parent route 'parent' loads fine but the nested child route 'parent.child' does not seem to load the controller thus not bind it to the view. It only shows the template 'raw' with the template interpolation tags {{}}.

I am using angular 1.5.6, ui-router 0.2.17, angular-material 1.0.8, webpack 1.13.1 and ocLazyLoad 1.0.9. I tried many suggestions given in this site and other sites but no luck. Also when I use the code below inside one of my route...It does not work.

ocLazyLoad.load({ name:'parent.module', files:['./parent/parent.module']});

Below is my ui-router setup parent child:

Parent Route

.state('parent', {
    url: '/parent',
    abstract: true,
    templateUrl: parentView,
    controller: 'ParentController',
    controllerAs: 'parent',
    resolve: {
        parent: ['$q', '$ocLazyLoad', function ($q, $ocLazyLoad) {

        var deferred = $q.defer();

        require.ensure([], function (require) {

            require('angular-material/modules/js/input/input.min');
            require('angular-material/modules/js/input/input.min.css');
            require('angular-material/modules/js/button/button.min');
            require('angular-material/modules/js/button/button.min.css');

            var module = require('./parent/parent.module');

            $ocLazyLoad.load({
                name: module
            });

            deferred.resolve(module);

        }, 'parent');

        return deferred.promise;

        }]
    }
})

Child Route

.state('parent.child', {
    url: '/child',
    templateUrl: childView,
    controller: 'ChildController',
    controllerAs: 'child',
    resolve: {
        child: ['parent', '$q', '$ocLazyLoad', function (parent, $q, $ocLazyLoad) {

            var deferred = $q.defer();

            require.ensure([], function (require) {

                var module = require('./child/child.module');

                $ocLazyLoad.load({
                    name: module
                });

                deferred.resolve(module);

            }, 'child');

            return deferred.promise;

        }]
    }
});

Below is the code of parent.module

'use strict';

require('material-design-icons/iconfont/material-icons.css');

var parentController = require('./parent.controller');

var moduleName = 'parent.module';

angular.module(moduleName, [
        'app.core',
        'material.components.input',
        'material.components.button'
 ])
    .controller('ParentController', parentController);

module.exports = moduleName;
ocombe commented 8 years ago

Is there a reason why you're mixing oclazyload & requirejs ? Anyway, you resolve the promise before ocLazyLoad has finished loading the component. The load function is async, you cannot be sure that it's resolved as soon as it's called (in fact you can be sure that it's not).

You should do something like that:

.state('parent.child', {
    url: '/child',
    templateUrl: childView,
    controller: 'ChildController',
    controllerAs: 'child',
    resolve: {
        child: ['parent', '$q', '$ocLazyLoad', function (parent, $q, $ocLazyLoad) {

            var deferred = $q.defer();

            require.ensure([], function (require) {

                var module = require('./child/child.module');

                $ocLazyLoad.load({
                    name: module
                }).then(function() {
                    deferred.resolve(module);
                });
            }, 'child');

            return deferred.promise;

        }]
    }
});

and you should probably do the same for the parent. And without require (much simpler imo):

.state('parent.child', {
    url: '/child',
    templateUrl: childView,
    controller: 'ChildController',
    controllerAs: 'child',
    resolve: {
        child: ['parent', '$ocLazyLoad', function (parent, $ocLazyLoad) {
            return $ocLazyLoad.load('./child/child.module');
        }]
    }
});
ghost commented 8 years ago

@ocombe, I am not using requirejs. I am using webpack's require.ensure syntax which is similar to require.js. I have added the code changes as you suggested. When I click my login button to login to my parent route, my parent module does not load the first time I click the 'login' button. I need to click the login button TWICE for the parent module to load. :(

I did try your simpler way but I got the following error: app.js:7713Error: [$rootScope:infdig] http://errors.angularjs.org/1.5.6/$rootScope/infdig?p0=10&p1=%5B%5D

I have also tried to load the parent and child module in the parent route using...

`ocLazyLoad.load(['parent.module','child.module']);`

and it gives me a similar error as above.

I am using require.ensure to create chunks for later loading. http://webpack.github.io/docs/code-splitting.html

I need to load a bunch of packages/modules using require() before I load my module with ocLazyLoad. Since I do not need that chunk until the user click on the route then I use require.ensure to build the module and then dynamically load it when needed.