Can you run an Angular service (or a function on that service) before anything else? Ideally, as soon as ng-app gets parsed.
Here's my use case: I'm writing an app that gets AJAX data from a server and then parses the data a hundred different ways. I would like to make the initial AJAX call before all the controllers get called? That way I just have all the data parsed and loaded in the service without me worrying about updating any controllers or whatever.
I would like to make the initial AJAX call before all the controllers get called
In Angular method run is fired before any controller is called
var app = angular.module('myApp',[]);
app.run(function($rootScope){
// ajax call and other stuff
}
In run method you can do any job like login to Facebook, token validation and so on
Reference
Configuration blocks (aka app.config) - get executed during the provider registrations and configuration phase. Only providers and constants can be injected into configuration blocks. This is to prevent accidental instantiation of services before they have been fully configured.
Run blocks (aka app.run) - get executed after the injector is created and are used to kickstart the application. Only instances and constants can be injected into run blocks. This is to prevent further system configuration during application run time.
docs.angularjs.org/guide/module
plnkr = http://plnkr.co/edit/WTNuWKSgj0bMR1dtUkto?p=preview
The best way to configure how your services behave is to use providers. so, assuming you already have a mydata from your ajax call, the plnkr above shows a running example...
myapp.config(['sayHelloProvider',function(sayHelloProvider){
// assuming your ajax retrievies mydata
var mydata = angular.fromJson( angular.element(document.getElementById('mydata')).html() );
// configure service
sayHelloProvider.SetMessage("Olah! rate is=" + mydata.rate);
}]);
Related
I'm using an app generated using ember-cli with simple-auth and I need to access controllers from an authenticator.
You don't want to pass your logged in user data to a controller. Chances are that user data will be used in multiple routes/controllers, so you need a globally available object (Ember Services can solve that use case). Luckily this is already handled by ember simple auth in its session object, that is where you want to store user data.
In any controller you should be able to do something like:
this.get('session.secure.email'); // version 0.8.X
Read about the session here: https://github.com/simplabs/ember-simple-auth#the-session That is what you want to work with.
If you really want to access some controller within an authenticator, you can use the container from within the authenticator's methods, like so:
SimpleAuth.Authenticators.Base.extend({
authenticate: function() {
var controller = this.container.lookup('controller:yourControllerName');
// rest of authentication logic
}
});
But as mentioned, it's better to save the data in the session or even in the store (if you're using ember-data) and retrieve the data from that resource.
I have an angular app with javascript code I can't touch (3rd party code).
I'd like to intercept the http messages from outside of angular. I have figured out how to get the controller and injector and can get the $http service, but I can't seem to get the $httpProvider so I can add an intercept something like here
Code I've got so far is (it's actually in a timeout but I left that out for brevity),
$(window).load(
...
var injector = angular.element('#myBody').injector();
var httpProvider = injector.get('$httpProvider ');
httpProvider.interceptors.push(function ($q) {
...
but httpProvider isn't defined, $http is defined but it's not the same as the provider - I'm fairly new to angular, so is there any way to get the provider? Version is 1.1.5
Just to close the question - as calebboyd said:
Perhaps you can extend the app.
angular.module("3rdPartyApp").config(function($httpProvider){...});
This works.
Looking for some help with a best practice.
I have a module which I am setting a few custom headers. No big deal here:
$httpProvider.defaults.headers.common['token'] = function() {
return token;
};
token is a value that I must $http.get() on the page load.
My intial thought was to put this in my controller, but after thinking about it, it more more sense to do it in the module configuration on page load where I am setting my custom headers:
var app = angular.module('app',['ngRoute', 'ngResource'],function($httpProvider) {
// Custom headers
});
My question is two part:
Is this the best way to do this?
If it is, how do I make a $http.get() request inside of the module config?
app.config, as you might have noticed, won't allow you to use services like $http (or any service you make yourself), it's run before they are defined. Try putting the call in your app.run instead. It is after config and it has no restrictions against using services.
If it is the right approach or not is harder to answer as it depends on the exact use-case. As $http-calls are asynchronous you cannot just call your backend when the app starts and be sure the token exists in your controllers or services, the http call might not have returned yet! This might be a problem for you if you expect to use the token right away.
A better option, again depending on use-case, might be to use a resolve-function on any route that needs the token. A route will holds off on loading any controller and template until the routes resolve-function has finished. Using this method you can then be 100% sure that the token exists once the controller is run.
This video has a good intro to resolves.
They can also be combined. Running the http-call in your app.run, and then using a resolve function to make sure it exists before the controller loads.
I have an app and I am utilizing routes to load two different views.
The first route #/ is the main list view. That works every time.
My second route is #/view/:id and loads my second view when a list item is clicked.
The view is data driven based off the id, all of which need to make $http requests through a service I created.
Is it possible that when I leave the #/view/:id route, it unloads that view completely and reloads it when I come back?
OR
How do I go about resetting promises inside a service so that the next time the view is loaded, it will request the new data?
These are not mutually exclusive questions. Routing with ngView destroys the view, scope, and controller on every load, so controller and scope history are not preserved among routes. Otherwise, memory load in the browser would be high; instead, we can use services to preserve the state we need to across all routes.
$http requests are made fresh every time they are called, unless the cache option is enabled. There shouldn't be any work required for this to work as designed:
.factory( 'dataService', function( $http ) {
return function dataServiceFn ( id ) {
return $http.get( '/myapi', { params: { id: id } } );
};
});
When your data service is called (e.g. dataService( $routeParams.id ); ), a new promise will be returned.
This is just a sample service structure for an incredibly simple case, but so long as the $http call is made fresh on each service call, you will get a new promise guaranteeing fresh data every time.
Angular will unload the controller when you leave to another controller. If you need to store the data between different view, you should store it inside the service (which is not unloaded when the controller changes) or be prepared to make an $http request every time you load the view.
I am using AngularJs for a new application. I feel I have solved a problem but i'm not sure i have done it in the best way possible so would like to check before gunning ahead.
Let's for examples sake say i have the two controllers AccountsCtrl and ContactsCtrl, every time each is called a request to a REST server for all the accounts or contacts is made for each controller respectively. When within the controller any data changes are kept in sync in the angular models (and the server backend) to reflect this and hence the UI. Every time the user switches between each controller they have to make call to the server to fetch the data which it already had (which was up to date) last time it was loaded.
Currently this causes a very small lag. I would like to make it persistant i.e. not loaded each time the controller is loaded to save on the lag and the server requests. I have tried saving the data into the $rootScope and this works great but i'm not sure it's the right thing to do?
The question is how best solve this problem? Is the $rootScope the best way to tackle this?
I would store the data and code that interacts with the web server in one or two Angular services. Each time a controller is created (e.g., when you go back to the page a second time), the (appropriate) service should decide whether to return the cached data or make an Ajax request to your REST server.
Your service(s) would be injected into your controllers.
See also https://stackoverflow.com/a/12009408/215945 and https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussion
First of all, you should do your REST call via a service:
app.factory('RestService', ['$http', function($http) {
return {
getSomething: function(url) {
var result = {};
$http.jsonp(url).success(function(data) {
result.list = data;
});
return result;
}
};
...
}];
You don't need $rootScope. Just define a parent controller which scopes both controllers, e.g. RootController, and store the data there. This is because child scopes (e.g. from AccountsCtrl) inherit what is defined in parent scopes.
<div ng-controller="RootController">
<div ng-controller="AccountsCtrl">
</div>
<div ng-controller="ContactsCtrl">
</div>
</div>
In practice this is almost the same as using $rootScope, but you don't need to inject it and you keep your controller logic similar as other controllers.