AngularJS Question

Execute a controller after main controller is executed

I have an index page

index.html
with its controller
indexController
. I set some value($scope.ipAddress) in a
factory
in the
indexController
which is used by other controllers of the html inside
ng-view
.

When the page is loaded, the
indexController
is supposed to execute first, set a value in the
factory
and then that value is used by other controllers of pages inside
ng-view
.

But I think the other controllers are executed first before
indexController
and I get undefined for the value I set.

This is the
indexController
with
factory
:

angular.module('tollApp')
.controller('indexController', function($scope,$http,$window,userDetailsFactory){
$scope.usernameFromServer={};
$scope.getUserDetails = function(){
$http({
method:'GET',
url:'http://192.168.1.80:4000/getUserDetails'
// url:'http://websitename.com/getUserDetails'
})
.then(function(response){

// console.log(JSON.stringify(response));
userDetailsFactory.setUserDetailsInFactory(response.data);
$scope.usernameFromFactory = userDetailsFactory.getUserDetailsFromFactory().usernameFromSession;
$scope.theIP = userDetailsFactory.getUserDetailsFromFactory().ipAddress;
// $scope.usernameFromServer = userDetailsFactory.getUserDetailsFromFactory().username;
// console.log(JSON.stringify($scope.usernameFromFactory)+"usernameFromFactory");
})
}
$scope.logout = function(request,response){
$http({
method:'GET',
url:'/logout'
})
.then(function(response){
console.log(JSON.stringify(response));
if(response.data=="logout"){
// $window.location.href="http://websitename.comlogin";
$window.location.href="http://192.168.1.80:4000/login";

}
})
}
console.log("indexController");
}).factory('userDetailsFactory',function(){
var user = {};
return {
setUserDetailsInFactory : function(val){
user.useridFromSession = val[0].UserID;
user.usernameFromSession = val[0].UserName;
user.userroleFromSession = val[0].UserRole;
user.clientidFromSession = val[0].ClientID;
user.ipAddress = "http://192.168.1.80:4000/";
// user.ipAddress = "http://websitename.com/";
// console.log("in set "+user.clientidFromSession);
},
getUserDetailsFromFactory : function(){
return user;
}
};
})


The other controller where I use the value from factory:

$scope.ipForHttp = userDetailsFactory.getUserDetailsFromFactory().ipAddress;
console.log($scope.ipForHttp); //undefined
$scope.loading = false;
$scope.ClientID = userDetailsFactory.getUserDetailsFromFactory().clientidFromSession;
// $scope.dev={};

$scope.getDevice =function(){
console.log($scope.ipForHttp); //undefined
$scope.loading = true;

$http({
method : "GET",
url : $scope.ipForHttp+"getDeviceDetailsReport"
}).then(function mySucces(response) {

Answer

Take a look at your $scope.getUserDetails - you're using $http (docs) service to make an asycronous AJAX call to the back-end.

The callback function you supply in the .then() method of the returned object may be executed sometime in the future or may even not - depends on whether the call succeeds or fails. You must not expect it to behave syncronously, because it never will, even if the backend responds instantly.

That's why you can't expect to have the desired data in your other controllers and need to adjust your code accordingly, e.g.

// tells angular to execute watcher function on every $digest
$scope.$watch(function () {
    // watches the returned value of the service's method
    return userDetailsFactory.getUserDetailsFromFactory();
}, function (newVal) {
    // filtering out empty object
    if (!Object.keys(newVal).length) {
        return;
    }

    // the following code will be run when
    // userDetailsFactory.getUserDetailsFromFactory
    // returns some value
    // in our particular case - after getting
    // data from backend and setting it in
    // userDetailsFactory.setUserDetailsFromFactory

    $scope.loading = false;
    $scope.ipForHttp = newVal.ipAddress;
    $scope.ClientID = newVal.clientidFromSession;

    $scope.getDevice();
},
// tells angular to watch properties of the object too
true);

Optionally, if you need to execute that code only once when user details are set, do this

var unbindUserDetailsWatcher = $scope.$watch(function () {
    return userDetailsFactory.getUserDetailsFromFactory();
}, function (newVal) {
    if (!Object.keys(newVal).length) {
        return;
    }

    unbindUserDetailsWatcher();
    unbindUserDetailsWatcher = null;

    ...
});
Comments