Skip to content

Instantly share code, notes, and snippets.

@marcoslin
Last active November 28, 2017 09:33
Show Gist options
  • Save marcoslin/b59cfa9a9a44bde04f9f to your computer and use it in GitHub Desktop.
Save marcoslin/b59cfa9a9a44bde04f9f to your computer and use it in GitHub Desktop.
ui-router: Lazy Loading State

Lazy Load States

Sample code for on how to lazy load state for ui-router

h4 {
color: blue;
}
a {
padding-right: 20px;
}
<!DOCTYPE html>
<html ng-app="lazyapp">
<head>
<title>Lazying Loading Routes</title>
<link rel="stylesheet" href="css_style.css">
</head>
<body>
<h3>Lazying Loading Routes: <a href="https://gist.github.com/marcoslin/b59cfa9a9a44bde04f9f" target="_blank">Source</a></h3>
<div ui-view></div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js" type="text/javascript"></script>
<script src="js_app.js" type="text/javascript"></script>
</body>
</html>
!function() {
var app = angular.module("lazyapp", ['ui.router']),
config_injector;
/**
* Configure state in 2 steps:
* 1. `app.config` will create `home` that leads to `view1` and `view2`
* 2. `LazyRoute` will configure sub-state `view1.profile` and `view1.interest`
*
* `LazyRoute` should be invoked in `View1Ctrl` to simulate the delegation nature
* of `$state` configuration.
*/
app.config(function($stateProvider, $urlRouterProvider, $injector) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'view_home.html',
controller: 'HomeCtrl'
})
.state('view1', {
url: '/view1',
templateUrl: 'view_view1.html',
controller: 'View1Ctrl'
})
.state('view2', {
url: '/view2',
templateUrl: 'view_view2.html',
controller: 'View2Ctrl'
});
$urlRouterProvider
.otherwise('/home');
// Cache injector
config_injector = $injector;
});
app.factory("LazyRoute", function ($log) {
config_injector.invoke(function ($stateProvider) {
$stateProvider
.state('view1.profile', {
url: '/profile',
templateUrl: 'view_view1_profile.html'
})
.state('view1.interests', {
url: '/interest',
templateUrl: 'view_view1_interest.html'
});
$log.log("Sub View1 state configured.");
});
return {};
});
/**
* When going directly to sub-state, load the parent state first then go to the sub-state.
* E.g.: If going to `view1.profile` and it doesn't yet exists, attempt to go to `view1`
* first then go to `view1.profile` if it exists.
*
* Note: The code below only works one level down. Need to improve it to recursively go down
* the route.
*/
app.run(function ($rootScope, $state, $log) {
// var scope = $rootScope.$new();
console.log("$stateNotFound configured.");
$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams) {
$log.log("$stateNotFound event: ", event);
$log.log("$stateNotFound unfoundState: ", unfoundState);
$log.log("$stateNotFound fromState: ", fromState);
$log.log("$stateNotFound fromParams: ", fromParams);
var toState = unfoundState.to,
toStateParent = toState;
if (toState.indexOf(".")) {
// Check if parent state is a valid state
var firstToState = toState.split(".")[0];
if ($state.get(firstToState)) {
$log.log("Parent state '" + firstToState + "' found for '" + toState + "'" );
toStateParent = firstToState;
// Load first the parent state
$state.go(toStateParent).then(function (resolved) {
// Only go to final state if it exists.
if ($state.get(toState)) {
return $state.go(toState);
} else {
// Go back to calling state
$log.log("Going back to ", fromState);
return $state.go(fromState.name);
}
});
event.preventDefault();
} else {
$log.error(toState + " state not found.");
}
};
});
});
/**
* Define controllers
*/
app.controller("HomeCtrl", function ($scope) {
$scope.message = "Message from HomeCtrl";
});
app.controller("View1Ctrl", function ($scope, $state, LazyRoute, $log) {
$log.log("view1 controller called with scope id " + $scope.$id);
$scope.isState = $state.is;
$scope.message = "Message from View1Ctrl with state";
});
app.controller("View2Ctrl", function ($scope, $log) {
$log.log("view1 controller called with scope id " + $scope.$id);
$scope.message = "A View2Controller Message";
});
}();
<h2>Home Page</h2>
<div>Message: {{message}}</div>
<hr>
<a ui-sref="view1">View 1</a>
<a ui-sref="view2">View 2</a>
<a ui-sref="view1.profile">View1Profile</a>
<a ui-sref="view1.notexists">View1NotExists</a>
<a ui-sref="view3">View3NotExists</a>
<h2>View1</h2>
<div>View Message: {{message}}</div>
<h3>Detail</h3>
<div ui-view></div>
<h4 ng-show="isState('view1')">View 1 Main Page</h4>
<hr>
<a ui-sref="home">Home</a>
<a ui-sref="view1.profile">Profile</a>
<a ui-sref="view1.interests">Interests</a>
<h4>Nested View: Interest</h4>
<h4>Profile SubView</h4>
<h2>View2</h2>
<div>View Message: {{message}}</div>
<hr>
<a ui-sref="home">Home</a>
<a ui-sref="view1.profile">View1Profile</a>
<a ui-sref="view1.notexists">View1NotExists</a>
<a ui-sref="view3">View3NotExists</a>
Copy link

ghost commented Jan 27, 2015

Nice job! It really helped me, tnx for sharing it ;)

@sukrosono
Copy link

thank marcos 😄

@CodeLiftSleep
Copy link

@frankie .success is deprecated, you should be using .then/.catch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment