Angular2 инъекция зависимостей, не вводящая услугу во время наследования класса

Я использую angular2 с Typescript. Я пытаюсь создать base class, который может быть унаследован другими классами, и в базовом классе вводится служба. До сих пор я не мог правильно получить ajaxService injected в base class, который находится inherited в user class. В частности, когда создается экземпляр пользователя, а затем метод save() вызывается из экземпляра user, следующая строка в base class: return _this._ajaxService.send(options); не работает, поскольку _ajaxService - undefined.

Вот user class, который расширяет 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);
  }
}

Вот 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);
    });
  }
}

Это работает отлично, за исключением того, что ajaxService не вводится в базовый класс. Я предполагаю, что это имеет смысл, поскольку пользователь создается не основанием.

Итак, как я могу использовать ajaxService в Base module, когда когда базовый модуль расширяется в другом классе?

Я думаю, когда я создаю экземпляр пользователя, вызывается конструктор в классе пользователя, но конструктор базового класса, который вводит эту услугу, не вызывается.

Здесь 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);
      });
    });

  }

}

Ответ 1

Это нормально, чтобы вводить службы в базу, но вы должны передавать их из класса User независимо. Вы не можете наследовать фактическое создание службы с базы, поэтому вам нужно передать ее на базу от пользователя. Это не ограничение TypeScript, а скорее особенность работы DI в целом.

Что-то вроде этого:

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

Если база создала службу для вас, вы не сможете повлиять на ее создание. Это отрицательно повлияло бы на многие преимущества DI в целом, поскольку вы потеряете контроль, делегируя управление зависимостями другому компоненту.

Я понимаю, что вы можете попытаться уменьшить дублирование кода, указав это в базе, но это противоречит принципу DI.

Ответ 2

Каждый класс в Angular 2, который вы хотите ввести, должен аннотировать. Если он не является компонентом, вы должны аннотировать его аннотацией @Injectable(). Если вы добавляете класс, который уже вводит другой класс, вы должны создать для этого поставщика.

import {Injectable} from 'angular2/core';
import {Base} from './base';
@Injectable()
export class User extends Base {
}

Я создал Plunker для вас, надеюсь, что он решит вашу проблему:

http://plnkr.co/edit/p4o6w9GjWZWGfzA6cv41?p=preview

(посмотрите на вывод консоли)

PS. Пожалуйста, используйте Observable вместо Promises