Using reusable models and injecting these where required in Angular - angularjs

Anyone know the best recommended way of creating models in a separate JavaScript file and have these injected into the controllers that need them, rather than creating the models on fly normally in the controller?
This would make it so much easier to pass around the model and you would know exactly what you was passing around.
I have some thoughts on using Services, and inject these where I need i.e. controllers.
Controllers would then pass these onto specific services to do any heavy lifting to keep my controllers nice and light.
Is services the only and recommended way to go ? Or is there a better alternative way ?
Any use of third-party libraries / modules would also be considered.

I think services are the way to go. Not only are they injectable but they are also Singletons - meaning wherever they are injected, the same instance is shared.
Example of a service which uses the $http service to make an asynchronous call to retrieve data:
app.factory('customerService', function($http) {
var customers = [];
$http({ url: 'api/customers/all', method:'GET'}).success(function(data) {
angular.copy(data, customers);
});
return {
customers: customers
};
});
In your controller or directive, you can then inject the service and bind customers to your scope:
app.controller('ctrl', function($scope, customerService) {
$scope.customers = customerService.customers;
});

The best way to do it is by service for couple of reasons.
If you use ng-view and routing the service is not reloading and your data is safe in service
It's easy injectable to controllers
Provides two-way data binding between controllers
working plunker with two-way data binding between controllers
http://plnkr.co/edit/pt2xwlYqvY3r840tHJ92?p=preview
NOTE: if you don't have a dot in your model you are doing something wrong ;)

I believe services are the best way for this.
I have used scope inheritance to place some methods that most of my app would need at once such as a routing method I attached these to the .run () method of my main module/app.
You could separate your models into separate modules if you needed to structure your app that way.

Related

Should I have more angular services or controllers?

I am developing an angular web game where I have a bunch of quests that use a single html template for the view. The problem I have is how to organize the Angular code.
Should I have only one controller (which will hold the non-quest-specific logic) and uses a bunch of services (one for each quest-specific logic)? The controller would probably have a big if/else block to use the right service for the chosen quest.
Or should I have one controller for each quest? That way we can use fewer services overall and share them among the various controllers for the quests.
Which one makes more sense and would potentially have the fewest code duplication? Could there be a better alternative to both?
I just suggest you to go for a controller per unit and build the services thinking as elements that you can share between controllers structuring them as functional independent shareable elements.
Quest 1 = controller 1 -> inject all services needed for that quest
Quest 2 = controller 2 -> inject all services needed for this one
.......
You can't share code between controllers. If you want to have less duplicated code you should create services so you can share code between them and the controllers.
A good description of angular controllers vs. angular services can be found in an earlier post
I would recommend using a controller for each quest. Inject services into each controller that are relevant to that particular quest. Although you'll still need to write services to share that data/logic with the controller, you can avoid the unnecessary service injections as well as that massive if/esle block

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 inject dependencies into services in angular.js?

I'm using AngularFire to create a web app. Several of my controllers use a lot of the same functions to access the data in Firebase, so I am trying to write a service so that I don't have to rewrite the same functions for every controller. The problem is that I can't seem to get the Firebase dependency into the service. I'm using the following code:
angular.module("myApp", ["firebase","ngDraggable"])
.factory("GetData",['$firebase','FirebaseConn',function($firebase,FirebaseConn){
$firebase(new Firebase("https://XXXX.firebaseio.com/")).$asObject().$bindTo(scope, "firebaseData");
return {
};
}]);
But when I try to run this, I get the following error:
Unknown provider: FirebaseConnProvider <- FirebaseConn
I am able to access Firebase through my controllers, so it's not a problem connecting to firebase.js or angularfire.js.
How should I inject Firebase into my service so I can access the data in all of my controllers? Or, is there a better way to go about this? I'm rather new to Angular so if there's a better way to share functions between my controllers I'm all ears.
You inject them precisely the same way that you do in Controllers and Directives.
This is a common error in AngularJS, and it means you're injecting something that isn't injectable. It almost always means either you missed a dependency (probably not in this case) or that you're asking for something that doesn't exist in the first place.
This is almost certainly your problem. You're asking for firebase and getting it, but it can't find FirebaseConn. What is that, some variable of yours that you're using to track your connection? Because you aren't using it, and the AngularFire docs I just looked at don't, either.
Consider something more like the following:
angular
.module("myApp", ["firebase", "ngDraggable"])
.service("firebaseManager",['$firebase', function($firebase) {
var ref = new Firebase("https://XXXX.firebaseio.com/"),
sync = $firebase(ref);
this.getData = function() {
return sync.$asObject();
};
});
Obviously, customize this to suit. Two comments:
You probably do want a service instead of a factory. This is a common point of confusion when you first start using AngularJS. You only need a factory if you plan to get involved in the instantiation of the service in some way. A service is just a shortcut form of a factory with the most common usage - the one you probably want.
You will now inject this service firebaseManager into your controllers. When you do, they will be able to call firebaseManager.getData() and any other methods you define. firebaseManager will be a singleton, so all of this will go through one common Firebase connection.

The best way to Mock Services in AngularJS to decouple REST calls

I am building a web application with AngularJS and have built out a AngularJS Service that my controller uses to create, retrieve, update, delete data from. I want to farm out the UI work to another developer, but I don't want them to require the dependencies that the AngularJS Service does. I'd like to build a Mock Service and just return mock data rather than call the live REST service.
My App is set up like this:
var myApp = angular.module('myApp', ['ui.bootstrap']);
My Controller currently hooks up to the Service using:
myApp.controller('TodoCtrl', function TodoCtrl($scope, $JSOMService) {
$JSOMService.DoStuff();
});
And my Service is defined like this
myApp.service('$JSOMService', function ($q, $http) { ... });
What the are best ways to handle switching out the service for another one? This is a little different from Unit Testing and I wondered if there are any common ways of doing this?
For now I'm just having a slightly different code base where I just switch out the Angularjs Service javascript files loaded to handle this.
You can get access directly to the provider service, which controls injections. It would look something like this, where $provide is injected:
$provide.value('$JSOMService', MockJSOMService());
This will basically say, whenever someone asks for $JSOMService, give them whatever was returned from MockJSOMService.
You can set this up at the when you set up your app. Like this:
myApp.run(['$provide', function($provide) {
$provide.value('$JSOMService', MockJSOMService());
}]);
This is basically how you could switch out services. Admittedly a little funky, but I hope this helps!

Maintain controller state in Angular like Durandal does?

I like that Durandal has Activate/Deactivate methods that get called on the VM and that the views can even be cached.
Is there a way to have this same features in Angular?
You can use a service / factory. These are singletons in AngularJS and you can inject them to the controller. Strictly have one service per controller and the service will be maintained between navigations to the view / controller.
http://docs.angularjs.org/guide/dev_guide.services.creating_services
The way this would work is that your controller would take myService as an injected dependency. Then you assign it to $scope as $scope.cache = myService. Then in your view you bind to cache.someProperty for elements that wanted cached.
Just as an aside:
You can even share services containing state data between controllers. Although I would recommend against this pattern, because it looks like global state. Services you share between controllers should ideally only provide functionality instead of being data objects. Unless you are specifically looking for a global data store :)

Resources