<!DOCTYPE html>
<html>
<head>
<script src="https://code.angularjs.org/1.5.3/angular.js"></script>
<script src="//unpkg.com/angular-ui-router@1.0.0-alpha.4/release/angular-ui-router.js"></script>
<script src="//unpkg.com/oclazyload"></script>
<script src="_main.js"></script>
<script src="_lazyLoadHook.js"></script>
<script src="home.comp.js"></script>
<title>Plunk demonstrating Lazy Loaded Components</title>
<link rel="stylesheet" href="styles.css" />
<script src="//unpkg.com/ui-router-visualizer"></script>
<script src="//unpkg.com/d3"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" />
</head>
<body ng-app="app">
<div ui-view>ui-view not populated</div>
<div class="header">
Current URL: <b>{{$location.url() }}</b> <br>
Current State: <b>{{$state.current.name }}</b> <br>
Current Params: <b>{{$state.params | json }}</b><br>
Go to state: <state-selector></state-selector>
</div>
<uir-transitions-view></uir-transitions-view>
<uir-state-vis-container></uir-state-vis-container>
</body>
</html>
"use babel";
// Here's a skeleton app. Fork this plunk, or create your own from scratch.
var app = angular.module('app', ['ui.router', 'lazyHook', 'ui.router.visualizer']);
app.config($stateProvider => {
$stateProvider.decorator("views", (state, parentFn) => {
// Call the parent views: builder.
// This thing takes a views: declaration and builds the internal view objects
let viewsObj = parentFn(state);
angular.forEach(viewsObj, (view, key) => {
if (view.component) {
// it has a component: declaration... let's
// decorate the results of the real template provider
// First, save a copy of the stock ui-router templateProvider
let realTemplateProvider = view.templateProvider
// Then, override the view's templateProvider with our own
view.templateProvider = [ "$injector", function($injector) {
// Invoke the original templateProvider to get the template
let realTemplate = $injector.invoke(realTemplateProvider);
console.log('original template: ', realTemplate);
// Use string replacement to add the ui-view
let newTemplate = realTemplate.replace("><", " ui-view><");
console.log('replaced template: ', newTemplate);
return newTemplate;
}];
}
});
return viewsObj;
})
})
// Empty config block. Define your example states here.
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home')
$stateProvider.state({
name: 'home',
url: '/home',
component: 'home'
});
$stateProvider.state({
name: 'lazy',
url: '/lazy',
component: 'lazy',
// This file is loaded before the state is entered
lazyComponent: 'lazy.comp.js'
});
$stateProvider.state({
name: 'lazy.foo',
url: '/foo',
component: 'foo',
// This file is loaded before the state is entered
lazyComponent: 'foo.comp.js'
});
});
app.run(function($state, $location, $rootScope) {
$rootScope.$state = $state;
$rootScope.$location = $location;
});
console.log("Scripts loading... ");
body {
margin-top: 6em;
}
.link {
text-decoration: underline;
color: blue;
}
.link:hover {
cursor: pointer;
}
.header {
position: fixed;
right: 0;
top: 0;
height: 6em;
width: 100%;
border-bottom: 1px solid gray;
}
"use babel";
let module = angular.module('app');
let template = `
<h1>lazy foo state loaded</h1>
<div ui-view></div>
`;
let component = {
template: template,
bindings: { input: '<' }
}
module.component('foo', component);
# UI-Router: Lazy load components
## Global hook
The global hook in `_lazyLoadHook.js` is invoked before any transition
which will *enter* a state with a `lazyComponent:` property.
The hook returns a promise to lazy load the file
from the state's `lazyComponent:` property.
The transition waits for the hook's promise to settle, then continues or fails.
"use babel";
let module = angular.module('app');
let template = `
<h1>home state loaded</h1>
<a ui-sref="lazy">lazy</a>
<a ui-sref="lazy.foo">lazy.foo</a>
`;
let component = {
template: template
}
module.component('home', component);
var lazymodule = angular.module('lazyHook', ['ui.router', 'oc.lazyLoad']);
lazymodule.run(function($transitions, $q, $ocLazyLoad) {
// Register global hook to lazy load components
// This function returns true if a state has a lazy component
function hasLazyComponent(state) {
return state.lazyComponent != null;
}
// This function lazy loads a state's component,
// then removes the lazyComponent metadata
function loadComponent(state) {
return $ocLazyLoad.load(state.lazyComponent)
.then(() => delete state.lazyComponent)
}
// This function lazy loads any lazy components
// for states being entered.
function lazyLoadComponents($transition$) {
let promises = $transition$.entering()
.filter(hasLazyComponent)
.map(loadComponent)
// return a promise for all the lazy components loading
return $q.all(promises);
}
// This criteria checks if any entering states have a lazy component
let transitionCriteria = { entering: hasLazyComponent };
// Register the global hook.
// This hook is run *before* the transition starts.
// The transition waits for the hooks promise to settle before continuing.
$transitions.onBefore(transitionCriteria, lazyLoadComponents)
});
"use babel";
let module = angular.module('app');
let template = `
<a ui-sref="home">home</a>
<h1>lazy state loaded</h1>
<a ui-sref=".foo" ui-sref-active="active">foo</a>
<div ui-view></div>
`;
let component = {
template: template
}
module.component('lazy', component);