I'm new to Angular and states and wrapping my head around ui-router. I've been doing it with jQuery for too long. In jQuery, I can load up something with ajax, then on the success, perhaps run another function. How do you do that with Angular?
For example, I have the following
var ivApp = angular.module('ivApp', ['ui.router']);
ivApp.config(function($urlRouterProvider, $stateProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'partials/partial-home.html'
})
});
Which simply loads up partial-home.html
into my ui-view
. But how to tell it to run a function once that is done? For example, I have authenticate.js
and a function authenticate()
. How do I run authenticate() once 'home' state has loaded?
Additionally, can I tell angular to only load authenticate.js for this state? Or should I have already loaded it in the template. I know that if I include the script in partial-home.html (eg <script src="authenticate.js"></script>
) chrome throws me an error about synchronous xmlhttprest being deprecated. So somhow in the config, can I declare authenticat.js as a dependency of the state or something like that?
At the moment I have worked out I can do something like:
ivApp.controller('authenticate', function($scope) {
// start authorisation
authenticate();
});
And then define the controller authenticate in my ui-router states. But is that how it's done? It works basically. My authenticate function is doing things like changing things in the DOM, but I read controllers shouldn't be used for this.
Thanks for any pointers
Let's break down into parts.
If you just want to load authenticate.js
in this particular home
state, use ocLazyLoad . It's one of the best way to load a resource lazily. And it works really well if ui-router too!
$stateProvider.state('index', {
url: "/", // root route
views: {
"lazyLoadView": {
controller: 'AppCtrl', // This view will use AppCtrl loaded below in the resolve
templateUrl: 'partial-home.html'
}
},
resolve: { // Any property in resolve should return a promise and is executed before the view is loaded
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('js/authenticate.js');
}]
}
});
If you want to run authenticate()
once the state is loaded, there are quite a number of ways to do it. One way of course is listening to the $stateChangeSuccess
event, but I would avoid using it since you know, global variables, and global variables are bad. I do not want to pollute my $rootScope
just because I have a really specific use case.
You can use resolve
in ui-router too. Resolve
is executed after the state is loaded and before the controller is instantiated. I would recommend to use this method as you can chain your promises together with ocLazyLoad
, if you are using it (which you should).
Manipulating DOMs after a state is loaded? Sure, that's what templateUrl
for! Design your template such that it accomadates to your authenticate()
functions. If you combine it with resolve
, there isn't really much of a problem separating concerns as you would already have executed authenticate()
before controller is loaded.
Edit: Adding in Plnkr
You want to first lazily-load authenticate.js
, and then use the function inside authenticate.js
to do something. Since resolve
in ui.router
executes promise chains in parallel, we have to chain them up, ie, load your jsfiles first, and then return your status of authentication.
We need to declare a deferred promise using $q
service. We then return this promise in the resolve, so that you controller is listening to one promise instead of two. Here is how:
$stateProvider
.state('Home', {
templateUrl: 'home.html',
controller: 'homeCtrl',
resolve: {
//need to chain our promises since we neeed to first load the authenticate.js
//and second, execute authenticate()
loadJsAndAuth: ['$ocLazyLoad', '$q', '$injector', function($ocLazyLoad, $q, $injector) {
//declare a deferred promise
var deferred = $q.defer();
//now load the authenticate.js
$ocLazyLoad.load('authenticate.js').then(
//load successful! proceed to use our authenticate function!
function(success) {
//since we already have loaded authenticatejs, now we can inject the service and use it
var authSvc = $injector.get('authenticateSvc');
//this is just a demo on how to authenticate.
//change this to banana to see the authenticate fail
var fruits = 'apple'
if (authSvc.authenticate(fruits)) {
//authenticate pass, resolve the promise!
deferred.resolve('authenticated!');
}
//authenticate fail, reject the promise
deferred.reject('authenticate failed');
},
//load of jsfiles failed! reject the promise.
function(error) {
deferred.reject('Cannot load authenticate.js')
})
return deferred.promise;
}]
}
})
And in your controller, you can get the resolved promises!
//you can get access to what is is being resolved by loadJsAndAuth
.controller('homeCtrl', ['$scope', 'loadJsAndAuth', function($scope, loadJsAndAuth) {
$scope.status = loadJsAndAuth // this is resolved promises.
}]);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.