You wish to share business logic between controllers.
Utilise a Service to implement your business logic and use dependency injection to use this service in your controllers.
The template shows access to a list of users from two controllers:
<div ng-controller="MyCtrl">
<ul ng-repeat="user in users">
<li>{{user}}</li>
</ul>
<div class="nested" ng-controller="AnotherCtrl">
First user: {{firstUser}}
</div>
</div>
The service and controller implementation in app.js
implements a user service and the controllers set the scope initially:
var app = angular.module("MyApp", []);
app.factory("UserService", function() {
var users = ["Peter", "Daniel", "Nina"];
return {
all: function() {
return users;
},
first: function() {
return users[0];
}
};
});
app.controller("MyCtrl", function($scope, UserService) {
$scope.users = UserService.all();
});
app.controller("AnotherCtrl", function($scope, UserService) {
$scope.firstUser = UserService.first();
});
You can find the complete example on github.
The factory
method creates a singleton UserService
, that returns two functions for retrieving all users and the first user only. The controllers get the UserService
injected by adding it to the controller
function as params.
Using dependency injection here is quite nice for testing your controllers, since you can easily inject a UserService
stub. The only downside is that you can’t minify the code from above without breaking it, since the injection mechanism relies on the exact string representation of UserService
. It is therefore recommended to define dependencies using inline annotations, which keeps working even when minified:
app.controller("AnotherCtrl", ["$scope", "UserService",
function($scope, UserService) {
$scope.firstUser = UserService.first();
}
]);
The syntax looks a bit funny, but since strings in arrays are not changed during the minification process it solves our problem. Note that you could change the parameter names of the function, since the injection mechanism relies on the order of the array definition only.
Another way to achieve the same is using the $inject
annotation:
var anotherCtrl = function($scope, UserService) {
$scope.firstUser = UserService.first();
};
anotherCtrl.$inject = ["$scope", "UserService"];
This requires you to use a temporary variable to call the $inject
service. Again, you could change the function parameter names. You will most probably see both versions applied in apps using Angular.