How to make controller wait untill app.run finishes - angularjs

In my application, I'm getting some data in app.run using $http.get()
The result from this is required to proceed to the controller.
Currently my controller is executing before the completion of this $http.get
How can I make my controller's execute after the execution of $http.get()
app.run(function ($rootScope, $http, $cookies) {
var currentLanguageId = angular.fromJson($cookies.get('mykey')).UserInfo.Country;
$http.get('myurl').then(function (serviceInfo) {
$rootScope.serviceURL = serviceInfo.data.serviceURL;
}, function (error) {
alert('error service info');
});

run can't handle asynchronous work at the moment. See this issue : https://github.com/angular/angular.js/issues/4003
You have multiple solutions for that. You can get your data without Angular and start Angular manually ( How to wait for a promise in a Run block in Angular? )
Or you can use the resolve of your route to do this : AngularJS : Initialize service with asynchronous data

You can use angular scope event. When data is fetched, you can broadcast an event from $rootScope to all controllers and receive this event in target controller.

You may use $rootScope.$broadcast();in the app.run and then use $rootScope.$on() in your controller.
app.run(function ($rootScope, $http, $cookies) {
var currentLanguageId = angular.fromJson($cookies.get('mykey')).UserInfo.Country;
$http.get('myurl').then(function (serviceInfo) {
$rootScope.serviceURL = serviceInfo.data.serviceURL;
$rootScope.$broadcast('serviceInfoReceived')
}, function (error) {
alert('error service info');
});
});
In your Controller
app.controller ('myCtrl' , function($rootScope) {
$rootScope.$on("serviceInfoReceived", function(){
console.log($rootScope.serviceURL)
});
})
Hope this may help you.

This is an old question, however the $rootScope.$on solution will not always work. It will depend on the timing of the controller registering the listener. The way I have found that works is to set a $rootScope property, and then configure a recursive timeout to wait for it to be set.
function waitForRun() {
if($rootScope.runFinalized){
// do something
} else {
$timeout(waitForRun, 500)
}
}
waitForRun();
and after the last .run block:
.run(function($rootScope) { $rootScope.runFinalized = true; })
Ugly, but it works.

Related

AngularJS inject complete event is needed

I am defining a service in AngularJS 1.2.x like below where I inject the DreamFactory API for use in this service. Now, when I do this, I get the error message like
TypeError: Cannot read property 'getRecords' of undefined
I interprete that the injection has not completely terminated. So I went ahead and delayed the call to the API 1000ms which solves the problem. But of course, this delay is not an acceptable solution.
Somehow I need an event for injection completion upon which I can then launch the DreamFactory.api.db.getRecord() method.
Can anyone help?
(function () {
'use strict';
angular
.module('app')
.service('VisitService', VisitService);
VisitService.$inject = ['$cookieStore', '$rootScope', '$timeout', 'DreamFactory'];
function VisitService($cookieStore, $rootScope, $timeout, DreamFactory) {
var service = {};
service.getVisits = getVisits;
function getVisits(callback) {
//setTimeout(function(){
DreamFactory.api.db.getRecords({table_name: 'visitors'})
.then(function(result) {
console.log(result.data.record);
callback(result.data.record)
},
function(reject) {
});
//}, 1000);
}
return service;
}
})();
in the controller, I call the service like so
VisitService.getVisits(function(result){
alert("this callback was triggered")
console.log(result)
});
DreamFactory uses, besides being a promise based API, another condition that one has to look for.
I do this with :
$scope.$on('api:ready', function (e) { }
This watcher being present solves my problem.
Thanks everybody who tried to help

Execute $http call in angular .run() finished after controller init

I am trying to make an $http call in order to store a JSON into $rootScope in the .run() function in an Angular app but the call is done after the controllers are loaded and I cannot use any of the data from the call. Can anyone help me with this issue?
Also tried to see what happens with console.log, the output is "b" then "a" and for $rootScope.xml is undefined
var app = angular.module('lobby', ['ngRoute']);
app.run(['$rootScope','$http', function($rootScope, $http) {
$http.get(Main.constants.BASEURL+'x.xml').success(function(xml) {
$rootScope.xml = $.xml2json(xml.data);
console.log('a');
});
}]);
app.controller('CategoriesController', function($rootScope) {
console.log($rootScope.xml);
console.log('b');
});
You can try placing a $watch on $rootScope.xml and listen for a new value, which should occur when the $http call resolves & xml scope variable value gets changed.
Code
app.controller('CategoriesController', function($rootScope) {
$rootScope.$watch('xml', function(newValue, oldValue) {
if($rootScope.xml) {
console.log($rootScope.xml);
}
});
});

AngularJS service with HTTP request, offline status

I have a AngularJS app with a service that load a HTTP request, that works all fine, but...
When my app is offline at the beginning, i show a "offline" page with a retry button, when i click the button and the APP is online I need the service to load the data.
The problem is that nothing happen when I click the button, the online check works fine but the web service is never called :(
my service:
.service('webService', function ($http, $q){
var defferer = $q.defer()
var webservice_url = "http://mywebservice_url/";
$http.get(webservice_url+"?action=get_settings").success(function(data) {
defferer.resolve(data);
});
return defferer.promise;
})
my controller:
.controller('NetworkCtrl', function($scope, $location, $timeout, webService) {
$("#tryagain-button").click(function(e) {
e.preventDefault();
if(checkifonline()) {
webService.then(function(data) {
$scope.data = data;
});
}
});
})
First of all, using jQuery within an controller is absolutely not how angularjs works. Use the ng-click directive. Even if your service would be implemented correctly, it wouldn't work since AngularJS will not get notified about model changes in the scope (you would need to use $apply, but just stick to the ng-click directive)
Second, the service function takes a constructor function. Within this constructor you're making an http request (while you're offline) and the promise is resolved. You will never make a new request, since the service always retuns the same promise. Your service should look like:
.service('webService', function ($http){
var webservice_url = "http://mywebservice_url/";
this.getSettings = function(){
return $http.get(webservice_url+"?action=get_settings");
};
})
and your controller:
.controller('NetworkCtrl', function($scope, $location, $timeout, webService) {
$scope.onClick = function(){
webService.getSettings().success(function(data){
$scope.data = data;
}
}
})
and your HTML button:
<button ng-click="onClick()">reload</button>

How do I broadcast from the http interceptor?

Using AngularJS 1.2
My interceptor looks like this:
$httpProvider.interceptors.push(['$q', '$log', '$rootScope', function ($q, $log, $rootScope) {
return {
'request': function(config) {
$rootScope.$broadcast('spin');
console.info('request!');
return config || $q.when(config);
},
...
In my nav controller (which handles and binds the loader/spinner to the view):
$rootScope.$watch('spin', function(event) {
console.info('spin');
$scope.spinner++;
});
The broadcast seems to happen only once at the end of all the responses received, even though I can see many request! in the console log.
How must I manage my global spinner/loader?
EDIT
I wish to show a loader/spinner in my navbar whenever data is being loaded.
The $watch function doesn't listen for broadcast messages. It watches for changes on the scope. In this case, you are calling a function whenever $rootScope.spin changes, which gets called (by default) immediately, which is why you got called once.
The $on function is what you want here, as it is what will listen to broadcast events.
$rootScope.$on('spin', function(msg, data) {
console.info('spin');
$scope.spinner++;
});
I've put together a complete working example if you are curious:
http://codepen.io/BrianGenisio/pen/wIBHz
Instead of using watcher you should just use on in the module run function
angular.module('test',[]).run(['$rootScope' function ($rootScope) {
$rootScope.$on("$spin", function () {
// set the spinner here
});
}]);

How do i use $on in a service in angular?

i have been able to get controller to use the $on listener
with $scope.$on.
but i don't see any documentation on how to get services to listen for events.
I tried $rootScope.$on, but that only allows one listener. i want listeners in multiple services regardless of whether their parent controllers are in scope or not.
after experimenting a fair bit it turns out that getting events to the service can be done with minimal code.
sample service code follows in case anyone else runs into this.
The sample saves and restores the service model to local storage when it gets the respective broadcasts
app.factory('userService', ['$rootScope', function ($rootScope) {
var service = {
model: {
name: '',
email: ''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
}]);
Since $on is a scope method, you could create a scope in your service, then listen for events on it:
app.factory('myService', function($rootScope) {
var scope = $rootScope.$new(); // or $new(true) if you want an isolate scope
scope.$on('testEvent', function() {
console.log('event received');
})
return {}
});
function MyCtrl($scope, myService, $rootScope) {
$rootScope.$broadcast('testEvent');
}
fiddle
However, I would not recommend this approach, since scopes are not normally associated with services.

Resources