Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 dependency injection, service not being injected during class inheritance

I'm using angular2 with Typescript. I'm trying to create a base class that can be inherited by other classes and within the base class, a service is injected. So far I can not get the ajaxService injected correctly into the base class that is being inherited into the user class. Specifically when a user is instantiated, and then the save() method is called from the user instance, the following line in the base class: return _this._ajaxService.send(options); doesn't work since _ajaxService is undefined.

Here is a user class that extends the base class:

import {Base} from '../utils/base';

export class User extends Base {

  // properties
  id = null;
  email = null;
  password = null;
  first_name = null;
  last_name = null;

  constructor(source) {
    _super.CopyProperties(source, this);
  }
}

Here is the base class:

import {Component} from 'angular2/core';
import {AjaxService} from './ajax.service';

@Component({
  providers: [AjaxService]
})

export class Base {

  constructor(private _ajaxService: AjaxService) { }

  // methods
  public static CopyProperties(source:any, target:any):void {
    for(var prop in source){
      if(target[prop] !== undefined){
          target[prop] = source[prop];
      }
      else {
          console.error("Cannot set undefined property: " + prop);
      }
    }
  }

  save(options) {
    const _this = this;
    return Promise.resolve()
    .then(() => {
      const className = _this.constructor.name
                            .toLowerCase() + 's';
      const options = {
        data: JSON.stringify(_this),
        url: className,
        action: _this.id ? 'PATCH' : 'POST';
      };

      debugger;
      return _this._ajaxService.send(options);
    });
  }
}

This works fine except that AjaxService is not being injected into the base class. I guess this makes sense since user is being instantiated not base.

So how can I use AjaxService in the Base module when when `Base module is being extended on another class?

I guess when I instantiate user, the constructor in the user class is called but the constructor in the base class that injects the service is not being called.

Here's the AjaxService:

   import {Injectable} from 'angular2/core';

@Injectable()

export class AjaxService {

  // methods
  send(options) {
    const endpoint = options.url || "";
    const action = options.action || "GET";
    const data = options.data || {};

    return new Promise((resolve,reject) => {
      debugger;
      $.ajax({
        url: 'http://localhost:3000' + endpoint,
        headers: {
          Authentication: "",
          Accept: "application/vnd.app.v1",
          "Content-Type": "application/json"
        },
        data: data,
        method: action
      })
      .done((response) => {
        debugger;
        return resolve(response);
      })
      .fail((err) => {
        debugger;
        return reject(err);
      });
    });

  }

}
like image 505
monty_lennie Avatar asked Dec 27 '15 07:12

monty_lennie


People also ask

What is difference between @inject and injectable?

We use the @Inject parameter decorator to instruct Angular we want to resolve a token and inject a dependency into a constructor. We use the @Injectable class decorators to automatically resolve and inject all the parameters of class constructor.

Is dependency injection the same as inheritance?

One criticism of inheritance is that it tightly couples parent class with child class. It is harder to reuse the code and write unit tests. That's why most developers prefer dependency injection as a way to reuse code. Dependency injection is a way to inject dependencies into a class for use in its methods.

What is injectable () in Angular service?

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.

What are the three types of dependency injection?

Types of DI There are three main styles of dependency injection, according to Fowler: Constructor Injection (also known as Type 3), Setter Injection (also known as Type 2), and Interface Injection (also known as Type 1).


1 Answers

It's ok to inject services in the base, but you have to pass it in from the User class regardless. You can't inherit the actual instantiation of the service from the Base, so you have to pass it down to the Base from User. This is not a limitation of TypeScript, but rather a feature of how DI works in general.

Something like this:

class User extends Base
  constructor(service: AjaxService) {
        super(service);
  }

If the Base instantiated the service for you, you would not be able to affect the instantiation from User. This would negate a lot of the benefits of DI overall since you would lose control by delegating dependency control to a different component.

I understand that you might be trying to reduce code duplication by specifying this in the Base, but this goes against the principle of DI.

like image 83
TGH Avatar answered Oct 20 '22 00:10

TGH