Robert Christian
Robert Christian

Reputation: 18310

Angular JS - Make service globally accessible from controllers and view

Let's say we have the following service:

myApp.factory('FooService', function () { ...

Then, from a controller, I would say:

myApp.controller('FooCtrl', ['$scope', 'FooService', function ($scope, FooService) { ...

The two-part question is:

  1. Global Accessibility: If I have 100 controllers and all need access to the service, I don't want to explicitly inject it 100 times. How can I make the service globally available? Only thing I can think of at the moment is wrapping it from within the root scope, which defeats the purpose.
  2. Accessibility from view: How can I access the service from within the view? This post suggests wrapping the service from within the controller. If I am going to that length, seems I ought to just implement the functionality right on the root scope?

Upvotes: 30

Views: 26487

Answers (3)

Robert Christian
Robert Christian

Reputation: 18310

Found a reasonable solution. Inject it into the bootstrap method (run), and add it to the root scope. From there it will be available to all controllers and views.

myApp.run(function ($rootScope, $location, $http, $timeout, FooService) {
    $rootScope.foo = FooService;
    ....

Re-reading the post I mentioned above, it didn't say "wrap" exactly... just "abstract", so I presume the poster was referring to this same solution.

For thoroughness, the answer to (1) is then:

myApp.controller('FooCtrl', ['$scope', function ($scope) { 
    // scope inherits from root scope
    $scope.foo.doSomething();
    ...

and the answer to (2) is simply:

{{doSomething()}}

Adding Christopher's comment to make sure it's seen:

@rob - According to best practices, the factory should be injected in to the controllers that need to use it, rather than on the root scope. As asked, question number one actually is the antipattern. If you need the factory 100 times, you inject it 100 times. It's barely any extra code when minified, and makes it very clear where the factory is used, and it makes it easier (and more obvious) to test those controllers with mocks, by having the required factories all listed in the function signature. – Christopher WJ Rueber Nov 25 '13 at 20:06

Upvotes: 41

Tonatiuh
Tonatiuh

Reputation: 2485

Complementing question #1 (Global accesibillity) I will only add that in order to avoid issues when minifiying the file (if that's the case) it should be written like this:

this.app.run(["$rootScope", "Foo", function($rootScope, FooService) {
    return $rootScope.fooService = FooService;
  }
]);

Upvotes: 6

James M
James M

Reputation: 480

As far as accessing the service directly in the view, that seems exceedingly un-angular. Binding it to a scope variable in the controller seems like a better solution than using the service directly in the UI to help maintain separation of duties.

Upvotes: 6

Related Questions