how to initialize application asynchronously in angular - javascript

I am writing an angular app that will need some asynchronous code to run during the bootstrap phase. Let's say that this pahe includes collecting several AJAX call responses. As the resources are being requested, there is an overlay icon shown (waiting for data). After all of the requests are done, the application is ready to start working. The question is: how to do this correctly in angular?
The things I've found in the web so far seem to be hacky, such as:
http://xcellerant.net/2014/10/30/initializing-global-variables-and-synchronous-ajax-calls-in-an-angular-xpages-application/ - here the author uses jQuery to run $.ajax synchronously, which is 100% what I don't want to do, because of obvious reasons.
https://blog.mariusschulz.com/2014/10/22/asynchronously-bootstrapping-angularjs-applications-with-server-side-data - here the author removes the ng-app from HTML to bootstrap the application manually. This is better then above, but still, quite hacky.
I am looking for a convenient and clean solution. In backbone (or anything built on top of it), for example, you may simply run several ajax requests inside initialize method. Backbone relies on jQuery afterall - or something complaint - so just collect them all asynchronously using $.when(list-of-promises) and fire an event that will asynchronously bootstrap the whole app. This is purely modular. And there are no hacks.

You don't need to delay bootstrapping your app.
You use $http service to request data. $http methods return promises. You can use the $q service's $q.all() method to wait until all the $http promises have resolved.
Something similar to this:
<body ng-app="app">
<div ng-if="!Initialized">
Overlay (waiting for data)
</div>
<div ng-if="Initialized">
Application
</div>
</body>
angular.module('app', [])
.run(function($rootScope, $q, $http){
$rootScope.Initialized = false;
$q.all({
firstRequest: $http.get('/someresource'),
secondRequest: $http.get('/someotherresoruce'),
thirdRequest: $http.get('/athirdresource')
}).then(function(results) {
$rootScope.resource1 = results.firstRequest;
$rootScope.resource2 = results.secondRequest;
$rootScope.resource3 = results.thirdRequest;
$rootScope.Initialized = true;
});
});
Note, this is to demonstrate how to wait for multiple $http requests concurrently and to change from a "loading" to a "ready" state. Using $rootScope is generally frowned upon as a way to share data across controllers.

Related

Start Angular.js route-segment or ui-router after all translations are loaded

Is there any way, how to start ui-router or route-segment just after translateProvider loads its translations?
I'm using pascal prechts translate filter together with bind once {{:: }} notation. On localhost it works pretty good, but when I test it on remote server, bind once will remove watchers sooner than strings are translated.
So I was wondering if there is some way how to delay routing a little bit.
Try to check the native, built-in feature:
$urlRouterProvider.deferIntercept(defer)
Disables (or enables) deferring location change interception.
If you wish to customize the behavior of syncing the URL (for example, if you wish to defer a transition but maintain the current URL), call this method at configuration time. Then, at run time, call $urlRouter.listen() after you have configured your own $locationChangeSuccess event handler.
Check some similar issues:
AngularJS - UI-router - How to configure dynamic views
can we add dynamic states to $stateprovider with already existing states in ui-router angular.js
In one of these links, observe this plunker, where this feature is used like this:
Stop and wait in .config() phase:
.config(['$urlRouterProvider' ...,
function($urlRouterProvider, ...) {
// defer execution in config phase
$urlRouterProvider.deferIntercept();
...
Later in .run() phase turn the url hanlding on
.run(['$urlRouter' ...,
function($urlRouter...) {
...
$http
.get("modules.json")
.success(function(data) {
// do some stuff
// re-enable UI-Router url stuff
$urlRouter.sync();
$urlRouter.listen();
});

Execute service before AngularJS bootstrap

Currently i would like to figure out, if it is possible to execute a additional service which executes an asynchronous call and bind the response in the current scope and afterwards bootstrapping my application.
I need this behavior, because i wanted to fetch some data from a server and bind this to the scope. I tried some solutions (like the resolve method in the ui-router component) but i couldn't solve it yet.
In addition i wanted to avoid to use the $watch method to observe the variable.
Anyone have a solution for this problem?
Thanks in advance.
Short of writing your own manual bootstrapping, you can't use a service before angular has been bootstrapped. But why do you need to? You can simply fetch the data after angular has bootstrapped, e.g. like Marvin Smit mentions in the comments, fetch it in your controller:
function MyCtrl($http, $scope) {
$http.get('whatever')
.then(function success(response) {
$scope.stuff = response.data
})
}
Angular's directives and interpolation are written with this in mind, and would not error if there's no $scope.stuff defined when the controller is executed.
Or you could use ngRoute/ui-router and the resolve parameter for a route(see https://docs.angularjs.org/api/ngRoute/provider/$routeProvider)

Notify AngularJS Controller about events from outside

New to Angular so I apologize if the question is silly.
So I'm making an app and one part of it is outside of Angular's "scope" so to speak and this part is responsible for receiving incoming messages (xmpp)
And then there is that Angular controller that has to be notified about incoming messages. What I did is an ugly work around but it works:
view.html:
<button ng-click="refreshLayout()" id="refreshLayoutButton" style="display:none"></button>
controllers.js:
.controller('chatCtrl', function($scope) {
$scope.refreshLayout = function() { ... }
})
outside.js:
if(incomingMessage) {
$("#refreshLayoutButton").click();
// append the message to view.html
}
Is there anyway to exclude jQuery? I want to send the message from outside.js to chatCtrl and then send it to view.html
OR
just notify about the event so it could invoke $scope.refreshLayout (techincally I can append incoming messages directly to view.html using jQuery without Angular, but the first option is still more preferable)
You should trigger event when there are incoming messages.
In outside.js use $broadcast when there are incoming messages.
In controller.js wait for that event to happen with $on.
Here's a simple example: http://jsfiddle.net/simpulton/XqDxG/
... technically I can append incoming messages directly to view.html using jQuery without Angular
I strongly recommend to use Angualrjs only. (For me I would remove jQuery and use only in specific cases in Directives). Angular itself includes jQuery-lite edition within it
New to Angular ...
Please follow this How do I “think in AngularJS” if I have a jQuery background? first, it will make things a bit clearer
So I hope outside.js: from your example means some Directive logic that gets event and need notify controller about.
We can listen on event into Directive and Directive can notify controller by using $eval for example. Here is basic example how $eval works: Demo Fiddle
However (for isolate scope) the other way is just to map event method. Please take a look on THIS example where Google maps notifies controller about zoom change event received.

At what stage in the angularjs lifecycle is the DOM completely loaded

I'm trying to wrap a native JavaScript functionality around an angularjs module and I need to bootstrap some code on DOMloaded event handler.
document.addEventListener("DOMContentLoaded",function(){
//bootstrapper code
})
I'm a little confused if this is needed in the angular domain or not or maybe I might just be repeating something that has already been called by angular which I could have simply attached my code to. If I put the bootstrapper code in the module's run block, will it achieve the same effect, the docs says
It is executed after all of the service have been configured and the injector has been created.
with respect to the DOMLoaded Event, has it already been fired at this time?
Anyone know anything about this?
angular.module('myApp', []).run(function($rootScope) { }); is similar to $(document).load(function() {}); in jQuery but if a part of the page is being rendered using XHR then run() method will not be helpful.
You either have to write your logic inside below event
angular.module('myApp', []).run(function($rootScope) {
$rootScope.$on('$viewContentLoaded', function() {
// here
});
});
Or you better off writing a custom directive depending upon what you have to achieve.

Bootstrap AngularJS app with data from the server

I have an AngularJS app and I'd like to pre load the $scope or $rootScope with application specific data before any of the controller code is executed. This would include stuff like roles, permissions, localizations, etc.
The only viable option I've found is to add the resolve object to EVERY one of my routes/controllers, I consider this to be a maintenance nightmare.
I also read about application.run(), however there is no way to get the dependencies from the service to resolve. Meaning you may call a service to your server in run, but it will not wait for the promise to finish before continuing on.
I feel like this is a pretty glaring problem with AngularJS.
Hopefully I'm just missing something obvious from the API.
Here is a very similar question, posted over the summer, no real solution was posted though.
AngularJS load data in app startup
Normally resolve is a good way to do if you want to do something with Angular first, then pause, then do other things with Angular.
But if you want to do something without Angular first, then start Angular, you could manually start Angular.js with angular.bootstrap. So that you can load your data first, then when you feel ready. Call angular.bootstrap() to start angular module.
What you have to prepare:
Remove ng-app="XXX" from your document.
Call angular.bootstrap() after everything is ready.
Doc for angular.bootstrap()
angular.module('myApp').controller('MYContoller', function ($scope)
{
$scope.init = function()
{
...
};
$scope.init();
}
This should work, you can also use ng-init, bit think that the docs state that you shouldn't

Categories