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
Related
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.
i am a beginner when it comes to angular
so here is the fiddle
http://jsfiddle.net/prantikv/knc6vrd9/1/
i have an simple app and as you can see i am just trying out the basics.
The example works fine on jsfiddle but when i run it on my machine i get a huge piece of error staring like this
Error: [ng:areq] Argument 'SimpleCont' is not a function, got undefined
And the ng-repeat doesnt show any output and the text input also doesnt work as well
i have run the page via a local wamp server as well and get the same result
Ommit creating a function, since angularjs is modular and provides you mechanism to create controllers, which can be used in applications.
So in your code, instead of:
function SimpleCont($scope){
$scope.nameList=[
{firstname:'john'},
{firstname:'jane'}
];
}
Create module and controller within it. First use module method from angular, which takes as first parameter name of module ( later to include in ng-app ) and as a second parameter dependency list, which in this situation is empty.
angular.module('myApp', []).
Then invoke controller function on module.
Module method always return itself, so you can add later another contorllers by using dot ..
controller('SimpleCont', function(){
this.nameList=[
{firstname:'john'},
{firstname:'jane'}
];
});
This is code instead of function, this code sets module and assign controller to it.
In your application to use module and created controller within it, set ng-app properly.
instead of:
<div ng-app>
use:
<div ng-app="myApp">
Generally good to know how to create controllers and modules in angularjs for beggining, because later you can learn other curious things like services, factories and also get to know what is $http service and how to use it for making ajax calls.
Also good to automate work thanks to grunt, karma and yeoman.
Here is good tutorial to start.
Here is about yeoman a tool you can use to work with angular.
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)
I am using angular file upload in a custom property editor for Umbraco 7.0.3. I am following this tutorial in order to create the editor.
I am quite new to angular, so my question maybe trivial for some of you: I cannot resolve dependency to file upload service in my controller soon enough. My HTML template looks like:
<div ng-controller="MyCustomController">
<input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>
The controller function would need $upload service as an argument, however I inject that service at the beginning of the function:
angular.module("umbraco")
.controller("MyCustomController", function ($scope, assetService, $upload) {
assetsService
.load([
"/App_Plugins/MyCustomPlugin/angular-file-upload.min.js",
])
.then(function () {
alert('upload service loaded');
});
$scope.onFileSelect = function ($files) {
alert('file selected');
}
});
So, it is definitely not right this way. I was trying to load the upload service before the controller initialization, however it loads asynchronously, so the service cannot get defined before the controller anyway.
How can I declare my controller function only after the upload service is loaded, or how can I get a reference to the service other than an argument?
Thanks,
EDIT
The only solution I've found so far was to include the actual file upload codebase into the controller of the custom property editor. I used this paper as a starting point for my own codebase for its simplicity. However I am still looking for the 'proper' way of loading an external module in this case.
Include your code as a service instead.
The code angular.module line can take extra parameters if you see its documentation page. It is here that you should look to include any third party libs. For example, I use ngTable - an AngularJS wrapper around a jQuery sortable and filterable table plugin. To include its usage, I have to add it as a service to the current application's module like so:
var app = angular.module("umbraco", ['ngTable']);
All I then have to remember to do is to reference the scripts, and I can use the code as though I had included the body of the code itself. Therefore, I presume that you would reference your service JS files, and write your code to reference the service like this:
angular.module("umbraco", "MyCustomController");
I would however rename the code as services rather than controllers.
It's a steep learning curve for AngularJS, and even when you've used it a lot, there are a lot of common gotchas. I hope this explains it a bit more.
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.