Как angular обрабатывает внедрение зависимостей для нескольких служб? - PullRequest
4 голосов
/ 07 марта 2020

Я создал абстрактный класс, который действует как базовый сервис для двух других моих сервисов. Ниже приведен фрагмент кода для этого абстрактного класса:

import { Injectable } from '@angular/core';

export interface Book {
  title: string;
  description: string;
  price: number;
} 
@Injectable({
  providedIn: 'root'
})
export abstract class BaseService {

      constructor() { }

      abstract getBooks(): Book[];

}

Далее следуют две службы, реализующие службу абстрактного класса: Первая служба:

export class NovelService implements BaseService {

      constructor() { }
      getBooks() {
            const novels: Book[] = [
                {
                  title: 'War and peace',
                  description: "War and Peace broadly focuses on Napoleon's invasion of Russia in 1812",
                  price: 550
                }
              ];

            return novels;
        }

}

Вторая служба:

export class ReferenceBookService implements BaseService {



constructor() { }
getBooks() {
        const referenceBooks: Book[] = [
            {
              title: 'Spring in Action',
              description: "Spring in Action, Fourth Edition is a hands-on guide to the Spring Framework",
              price: 600
            }
          ];

        return referenceBooks;
    }

}

Теперь, в моем компоненте, по нажатию кнопки мне нужно решить, какой сервис нужно внедрить, и, соответственно, выполнить функцию «getBooks ()» для печати списка в html.

Я попытался использовать атрибут «useClass» в массиве провайдеров следующим образом:

import { Component, OnInit } from '@angular/core';
import { Book, BaseService } from '../../services/base.service';
import { NovelService } from '../../services/novels-service';
import { ReferenceBookService } from '../../services/reference-book-service';
let IS_NOVEL_MODE = true;
export function setValue(somevalue) {
  IS_NOVEL_MODE = somevalue;
}
@Component({
  selector: 'app-book',
  template: `<div *ngFor="let book of books">
  <h3>{{ book.title }}</h3>
  <p>{{ book.description }}</p>
</div>
<button (click)="changeMode()">click me!</button>`,
  styleUrls: ['./book.component.css'],
  providers: [{provide: BaseService, useClass: IS_NOVEL_MODE ? NovelService : ReferenceBookService}]
})
export class BookComponent implements OnInit { 
      books: Book[];
      isNovelMode = false;
        constructor(private _baseService: BaseService) { }

          ngOnInit() { 
            this.books = this._baseService.getBooks();
          }
          changeMode() {
            setValue(!this.isNovelMode);
          }

}

Мне нужен способ обновления массива провайдеров или просто атрибут «useClass» каждый раз, когда я нажимаю кнопку.

В двух словах, имея абстрактный класс BaseService и "NovelService" и "ReferenceBookService" в качестве их реализации, как я могу динамически решить, какой из них будет добавлен в мой компонент?

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Если вы используете providedIn: 'root' для своих услуг, то у Injector наверняка есть они, и вы можете просто get их:

constructor(private injector: Injector) {}
...
this.myService = this.injector.get(MyService);

И тогда вам не нужно вводить baseClass. Также удалите @Injectable из него

0 голосов
/ 07 марта 2020

Думаю, нет, инъекция происходит при создании компонента. Вы можете прочитать здесь для более подробной информации https://medium.com/angular-in-depth/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d

Я бы сделал это немного по-другому. Я бы создал один сервис, который получает URL [или тип] в качестве параметра, и вы можете динамически решать, какой сервис вам нужен

...