Initialize angular application with requests - angularjs

In my application I need to make a couple of request, using $http, and store the data in the $rootScope before the routes is executed. Is there a way to do this?

There is the run method:
angular.module('yourModule').run(['$rootScope', '$http',
function($rootScope, $http) {
$rootScope.foo = 'foo';
}
]);
This is executed before the routing starts.
HOWEVER, it is not good practice to store lots of global data in the $rootScope. It is better to use a service (also possible in the run method) and inject the service in your controllers only when you really need it.

Related

Testing angular controller with many dependencies

I've started testing my Angular app and have question that bother me a lot. For example I have controller (mainController) which is injecting 2 services: authService, configService.
Before testing I should prepare something like that:
describe('controller: testController with testService mock', function() {
var controller, authService, configService;
beforeEach(module('app'));
beforeEach(inject(function($controller, _authService_, _configService_) {
authService = _authService_;
configService = _configService_;
controller = $controller('mainController');
}));
it('should be registered with all dependencies', function() {
expect(controller).to.be.defined;
expect(authService).to.be.defined;
expect(configService).to.be.defined;
});
}
And that's totally clear for me. What if one of services or both have their own dependencies (services) ? Of course I'm gonna add it by passing through the inject function. In small apps that's no big problem. I'm adding as much services as I need. But the question is what if that services are injecting other services and others injecting others and there is a huge hierarchy ? What if we must add 30 services and we can't make a mistake because otherwise it's not gonna work ?
To be honest I've search a lot but there are many testing examples and tutorials but every single one is based on totally basic apps with few controllers and services.
Is there a painless way to handle this ? Maybe there is a way to skip some dependencies or force to automatically inject services with it's dependencies ?
What if one of services or both have their own dependencies (services) ? Of course I'm gonna add it by passing through the inject function
No, you won't. Angular will instantiate these services and inject them where they need to be injected, provided they're in the 'app' module or in one of its dependencies.
There's no reason to inject any service into your test, unless you need to do something with them, like calling one of their methods, or spying them.

How do you connect server side properties into angular controller

I'm using the yeoman meanjs generator and am a bit confused. In my core Angular controller I have this setup:
angular.module('core').controller('HeaderController', ['$scope', 'Authentication', 'Menus',
function($scope, Authentication, Menus) {
$scope.authentication = Authentication;
$scope.isCollapsed = false;
$scope.menu = Menus.getMenu('topbar');
$scope.toggleCollapsibleMenu = function() {
$scope.isCollapsed = !$scope.isCollapsed;
};
// Collapsing the menu after navigation
$scope.$on('$stateChangeSuccess', function() {
$scope.isCollapsed = false;
});
}
]);
How does the Authentication object come into scope here? Where is created ?
For example if I wanted to add an object say foobar which was from my MongoDb what's the standard practice of getting this data into the angular controller from the server size?
David
Authentication is a service defined in the services folder which sits alongside to the controller folder you are in. Here is the service definition:
angular.module('users').factory('Authentication', [
function() {
var _this = this;
_this._data = {
user: window.user
};
return _this._data;
}
]);
What you see here is the standard way of referencing services in your controllers. In angular, you typically have services that have business layer logic including logic to talk to the backend over restful protocols.
To reference it, you simply give the name of the service in the controller definition and that service reference is made using dependency injection. There is an injector that runs behind the scene to find the service by that name, and create a reference to it.
So any other service that you create, create just like this Authentication service and then just put the name of the service in the controller definition in a similar fashion to use the service.
Now something referencing the MongoDb database does not make sense here as this is the front end portion of the stack. This code executes on the client browser and not the server.
The MongoDb database sits on the server and all the code that you see in the app folder in this stack is the server side code. All the code in the public folder is the front end code. Hope this helps.
I have not used this particular generator (I use angular-fullstack-gennerator). But it is likely similar.
Yours seems you need to use a CRUD sub generator. That will give you the ability to crate, read, update and delete. So what ever you call it you will then import this into the controller you need it in.
If you called it CRUDserverstuff, you could then import it like the line below:
angular.module('core').controller('HeaderController', ['$scope', 'Authentication', CRUDserverstuff, 'Menus',
function($scope, Authentication, CRUDserverstuff, Menus) {
//use it as you would any other objecte here
CRUDserverstuff.post(myData);
}
I am new to angular as well so one thing I am not sure of is if it needs to be or even should be put twice like that on the import lines. That confuses me a bit.
If you are not tied to using the MEAN stack generator I found the fullstack one very friendly to a beginner. The one thing to be careful to learn is the file structure. Full disclosure: I an NEW to angular and the MEAN stack. This is also my first answer ever on here so there you go.

How do you make AngularJS built-in services available globally?

Code ...
angular.module('appName').factory('serviceName', ['$http', function ($http) {
Here, I am making Angular's $http service available to my service but how do I make it available to all services in my app without having to define it every time in every service within the app (assuming every service in my app needs access to $http)?
Please could code samples be provided. Many thanks in advance
There seems to be very little help on this issue.
angular.module('appName').factory('globalize', ['$http', function ($http) {
window.$http = $http;
}]);
e.g
http://plnkr.co/edit/HbyX2Bx8c3TNJyvL2ljf?p=preview
there you go, it's global now. But this is not the best thing to do...

Detecting page unload in angularjs

I have a javascript object which I need global to my angularjs application. When the application is about to be unloaded (due to a page refresh or some other scenario), I would like to persist the object to browser storage. I believe adding the object to $rootScope would fulfill the first requirement of making the object global, but writing the object to storage during the onbeforeunload event, would require access to the $rootScope variable. Is it possible to detect a page unload event in angularjs?
This should do it, but I also suggest avoiding $rootScope as global state is discouraged, and you might also wrap localStorage in a service so that it can be injected and mocked for testing.
.run([
'$window',
'$rootScope',
function($window, $rootScope) {
$window.addEventListener('beforeunload', function() {
localStorage.myValue = $rootScope.myValue;
});
}
]);

What is the best/easiest way to redefine a built-in angular service?

In our app, we are making cross domain requests, and so we have to use CORS. Since IE does this in a non-standard way, we created our own service (which has a dependency on $http for non-IE requests) that would handle all this for us. This all works fine within this app. However we have some non-app specific library code that needs to make requests. So, if these services in our library code simply use $http, the requests would not work in the app that needs to do CORS. However, we don't want these services injecting our CORS service, because that would break requests in apps that aren't doing cross-domain requests.
With all that being said, my end goal is to have the library code inject and use $http for all necessary requests. Then, in the specific apps, it could define how $http works. I initially thought I could just redefine the provider for $http. Something like this:
angular.module("myCorsApp").provider("$http", function() {
return {
$get: function(CORShttpService) {
return CORShttpService;
}
}
});
However, this results in the following error:
Circular dependency: CORShttpService <- $http <- $compile
I'm not sure I understand where the circular dependency is coming from. Does $compile have a dependency on the providers or something?
My real question is if I'm even going about this the right way. If there wasn't the circular dependency, I would think this would accomplish exactly what I want. Is there some workaround I can do to make this work? Is there a better/more correct way of doing this?
If it helps at all, the CORShttpService has the following dependencies: $q, $rootScope, $http, $timeout. Thanks for any help.
After digging around a bunch in the Angular docs, I decided that the best approach here was to "decorate" the $http service. This done with the decorator function of the $provide service. So, I ended up with something like this:
angular.module("myCorsApp").config(function($provide) {
$provide.decorator("$http", ["$delegate", "$q", "$rootScope", "$timeout", function($http, $q, $rootScope, $timeout) {
return function(requestConfig) {
//CORS logic using $http (basically what was the CORShttpService)
}
}]);
});

Resources