Skip to content

Lazy loading of states defined in child components

Gan Lu edited this page Oct 3, 2016 · 2 revisions

If you have states defined in a child component which is lazy loaded, the states are not available before the component is loaded. That means you cannot $state.go to the lazy loaded states or navigate to the URL corresponding to the state directly.

Consider the following scenario:

-- home/
---- posts/
------ posts.component.js
------ posts.js                // defined the child state "home.posts", with URL "/home/posts".
---- profile/
------ profile.component.js
------ profile.js              // defined the child state "home.profile", with URL "/home/profile".
---- home.component.js
---- home.js                   // defined the parent state "home".

Now that we added code splitting point in "home.js" and lazy loaded "posts" and "profile" with oclazyload, we cannot go to "/home/profile" directly in a browser since the state definition is not loaded yet.

To solve this problem we could use the Future State feature provided by ui-router-extras to implement the lazy loading of states with a few lines of code:

    // home.js
    
    import angular from 'angular';
    import uiRouter from 'angular-ui-router';
    import 'ui-router-extras/release/modular/ct-ui-router-extras.core';
    import 'ui-router-extras/release/modular/ct-ui-router-extras.future';
    import 'oclazyload';
    
    let homeModule = angular.module('home', [
      uiRouter,
      "ct.ui.router.extras.future",
      "oc.lazyLoad"
    ])

    .config(($futureStateProvider, $compileProvider) => {
      "ngInject";
    
      $futureStateProvider.futureState({
        'stateName': 'home',
        'urlPrefix': '/home',
        'type': 'homeState'
      });

      $futureStateProvider.stateFactory('homeState', ($q, $ocLazyLoad) => {
        "ngInject";
    
        let deferred = $q.defer();
    
        // Webpack code splitting point
        require.ensure([], function(require){
    
          // In babel 6 ".default" must be manually added
    
          let postsModule = require('./posts/posts').default;
          let profileModule = require('./profile/profile').default;
    
          let homeComponent = require('./home.component').default;
    
          $ocLazyLoad
            .inject([
              postsModule,
              profileModule
            ])
    
            .then(() => {
              $compileProvider.component('home', homeComponent);
            })
    
            .then(() => {
              deferred.resolve({
                name: 'home',
                url: '/home',
                component: 'home'
              });
            });
    
        }, 'home');
    
        return deferred.promise;
      });
    })
    .name;
    
    export default homeModule;
Clone this wiki locally