Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I inject a dependency in a class definition of a component?

I have this class-defined component (transpiled later by webpack and babel back into ES5). I need to use the $http service in one of its methods. How do I do that? Where do I inject $http as a dependency? If I do it in the constructor arguments, I get an error as if I hadn't injected it at all. Maybe classes is not the way to go here?

angular.module('myApp').component('home', {
    template: require('./home.component.html'),
    controller: class HomeCtrl {
        constructor() {
        }
        doMe() {
            $http.get('http://www.yahoo.com/');
        }
    }
});
like image 472
alexk Avatar asked Dec 16 '16 06:12

alexk


People also ask

Can a component be injected?

A component is injectable by default @Component() (or @Directive() ) includes @Injectable() . Don't expect to get a specific instance of a component injected. This works for example with constructor(@Host() private parentComponent) where DI lookup is limited to parent injectors up to the injector of the host element.

Which component can be injected as a dependency?

Which Component can be Injected as a Dependency In AngularJS? In Angular. JS, dependencies are injected by using an “injectable factory method” or “constructor function”. These components can be injected with “service” and “value” components as dependencies.

Which will inject services into component class?

The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency. Likewise, the @Injectable() decorator indicates that a component, class, pipe, or NgModule has a dependency on a service. The injector is the main mechanism.


2 Answers

ES2015 classes (or transpiled classes) are just syntactic sugar over prototypal inheritance. What this means is that the methods you define are put on the prototype of the "class". In order to be able to access the dependencies injected in the constructor, you need to somehow store them for later reference by the prototype method.

This is usually done by putting them on the instance:

function HomeController($http) {
  this.$http = $http;
}
HomeController.prototype.doMe = function() {
  this.$http.get('http://www.yahoo.com/');
};

In class-based syntax this translates to:

class HomeController {
  constructor($http) {
    this.$http = $http;
  }

  doMe() {
    this.$http.get('http://www.yahoo.com/');
  }
}

EDIT:
If you are using TypeScript, you can save some boilerplate by using access modifiers on the constructor arguments. E.g.:

class HomeController {
  constructor(private $http) {}
}

...which is shorthand for:

class HomeController {
  private $http;

  contructor($http) {
    this.$http = $http;
  }
}

EDIT 2:
If you want to make your controller minification-friendly, you can use one of the options described here (possibly along with a tool like ngAnnotate). For example, this is how you could use the "$inject Property Annotation" method:

ES5

HomeController.$inject = ['$http'];
function HomeController($http) {...}
HomeController.prototype.doMe = function() {...}

ES2015

class HomeController {
  constructor($http) {...}

  doMe() {...}
}
HomeController.$inject = ['$http'];

// OR

class HomeController {
  static get $inject() { return ['$http']; }
  constructor($http) {...}

  doMe() {...}
}

TypeScript

class HomeController {
  static $inject = ['$http'];
  constructor(private $http) {}

  doMe() {...}
}
like image 160
gkalpak Avatar answered Sep 19 '22 07:09

gkalpak


The class should have explicit $inject annotation in order to be properly minified:

class HomeCtrl {
    static get $inject() {
        return ['$http'];
    }
    // or unstandardized shortcut:
    // static $inject = ['$http'];

    constructor($http) {
        this.$http = $http;
    }

    doMe() {
         this.$http...
    }
}
like image 26
Estus Flask Avatar answered Sep 20 '22 07:09

Estus Flask