Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tell AngularJs to return a new instance via Dependency Injection

Tags:

The use case is simple: I have two controllers sharing the same dependency MyService. This service is holding some state, lets sat myVariable. If I set it from ControllerOne, then it will be also spotted by ControllerTwo.

What I want is for each controller to have it's own instance of MyService, so that myVariable can be changed by each Controller without affecting the other.

To put it in another words - I want new instance to be returned by Dependency Injection, rather than singleton.

like image 984
ŁukaszBachman Avatar asked Nov 28 '12 12:11

ŁukaszBachman


People also ask

Does AngularJS use Dependency Injection?

Dependency Injection is pervasive throughout AngularJS. You can use it when defining components or when providing run and config blocks for a module.

Which object does the Angular injector use to create an instance of dependency?

The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.

What does @inject do in Angular?

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. Injecting ChatWidget component to make the component behave like a singleton service so that the component state remain same across the app.

How do I inject a module in AngularJS?

There is one more way to inject dependencies in AngularJS: by using the $inject service. In doing so, we manually inject the dependencies. We can inject $scope object dependencies using the $inject service as shown in the listing below: function ProductController($scope){ $scope.


2 Answers

Not as directly has you might hope. Service instances are created the first time they're retrieved by the injector and maintained by the injector... in other words, they're always singletons. The magic happens in here, particularly look at the provider function, which puts the provider instance in the providerCache object.

But don't lose hope, you could just as easily add constructors for whatever it is you want to share in a Service, if you so chose:

app.factory('myService', [function() {      var i = 1;       function Foo() {         this.bar = "I'm Foo " + i++;      };       return {           Foo: Foo      }; }]);  app.controller('Ctrl1', function($scope, myService) {   $scope.foo = new myService.Foo();   console.log($scope.foo.bar) //I'm Foo 1 });  app.controller('Ctrl2', function($scope, myService) {   $scope.foo = new myService.Foo();   console.log($scope.foo.bar) //I'm Foo 2 }); 

EDIT: as the OP pointed out, there is also the $injector.instantiate, which you can use to call JavaScript constructors outside of your controller. I'm not sure what the implications are of the testability here, but it does give you another way to inject code that will construct a new object for you.

like image 69
Ben Lesh Avatar answered Oct 29 '22 00:10

Ben Lesh


There are plenty of general options for modularizing JavaScript code, but if you want to do something that relies solely on AngularJS, this pattern works:

1) First define the class that you want to inject multiple times:

function MyClass() {
  // ...
}

MyClass.prototype.memberMethod = function() {
  // ...
}

2) Next, make the constructor available as a constant:

angular.module('myModule').constant('MyClass', MyClass);

3) Finally, use the factory pattern to create named, injectable instances of the class:

angular.module('myOtherModule', ['myModule']).factory('instanceOfMyClass', [
   'MyClass', 
   function(MyClass) { return new MyClass(); }
]);
like image 30
karlgold Avatar answered Oct 29 '22 02:10

karlgold