Angular 8 - сервисный впрыск и заводская схема - PullRequest
0 голосов
/ 27 марта 2020

Я кратко просмотрел несколько статей и официальных Angular руководств, но похоже, что они не могли помочь мне решить мою задачу. И вот что я хотел и сделал.

Допустим, у меня есть приложение Angular со списком продуктов. Кроме того, это приложение будет иметь страницу со списком категорий и несколько страниц со списком N в будущем. Как вы можете видеть, они очень похожи и имеют один общий компонент - таблицу данных.

<app-data-table [type]="'product'"></app-data-table>

Который реализован так:

import {Component, Input, OnInit} from '@angular/core';
import {DataFactoryService} from "../data-factory.service";

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {

  @Input() type: string;

  private data: any[];

  constructor(private dataFactory: DataFactoryService) { }

  ngOnInit(): void {
    this.dataFactory.getServiceBy(this.type).selectAll();
  }

}

Так что, как вы уже догадались, я предназначен для того, чтобы сделать этот компонент службы типа агности c. Вот почему я создал и внедрил это DataFactory:

import { Injectable } from '@angular/core';
import {ProductService} from "./product.service";
import {CategoryService} from "./category.service";
import {DataService} from "./data.service";

@Injectable({
  providedIn: 'root'
})
export class DataFactoryService {

  private serviceTokenMapping = {
    "product": ProductService,
    "category": CategoryService
  };

  constructor() { }

  public getServiceBy(token: string): DataService {
    return new this.serviceTokenMapping[token];
  }
}

И, наконец, у нас есть два сервиса для продуктов и категорий с некоторым простым базовым c абстрактным классом:

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

@Injectable({
  providedIn: 'root'
})
export abstract class DataService {

  abstract selectAll(): any[];
}

import { Injectable } from '@angular/core';
import {DataService} from "./data.service";
import {Product} from "./product";

@Injectable({
  providedIn: 'root'
})
export class ProductService implements DataService {

  constructor() {}

  public selectAll(): Product[] {
    console.log(`ProductService...`);
    return [];
  }
}

import { Injectable } from '@angular/core';
import {DataService} from "./data.service";
import {Category} from "./category";

@Injectable({
  providedIn: 'root'
})
export class CategoryService implements DataService {

  constructor() {}

  public selectAll(): Category[] {
    console.log(`CategoryService...`);
    return [];
  }
}

Самое смешное, что эта реализация работает именно так, как и ожидалось. Поэтому я передаю тип таблицы в качестве продукта для страницы, связанной с продуктом, тип категории для категории et c.

Вопрос в том, сделал ли я что-то неправильное с точки зрения стиля Angular (провайдеры, DI et c.) И есть ли у нас способ реализовать такое требование, чтобы оно было больше Angular -i sh?

1 Ответ

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

Я думаю, что вы на самом деле создаете ProductService и CategoryService каждый раз, когда запускаете this.dataFactory.getServiceBy(this.type), и фактически не используете внедрение зависимостей в Angular.

. Вы можете использовать свойство providers для @NgModule чтобы указать токен для каждой зависимости и извлечь зависимость, используя @Inject или injector.get.

export interface DataService {
  selectAll(): any[];
}

@Injectable({
  providedIn: 'root'
})
export class ProductService implements DataService {
  public static TOKEN = new InjectionToken<DataService>('ProductService_TOKEN');
  constructor() {}

  public selectAll(): Product[] {
    console.log(`ProductService...`);
    return [];
  }
}

@Injectable({
  providedIn: 'root'
})
export class CategoryService implements DataService {
  public static TOKEN = new InjectionToken<DataService>('CategoryService_TOKEN');
  constructor() {}

  public selectAll(): Category[] {
    console.log(`CategoryService...`);
    return [];
  }
}

@NgModule({
    providers: [
     {
        provide: ProductService.TOKEN,
        useExisting: forwardRef(() => ProductService),
        multi: false
     },
     {
        provide: CategoryService.TOKEN,
        useExisting: forwardRef(() => CategoryService),
        multi: false
     }
   ]
})
export class YourModule {}

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {

  @Input() type: string;

  private data: any[];

  constructor(
     @Inject(ProductService.TOKEN) private dataService: DataService,
     private injector: Injector
   ) { }

  ngOnInit(): void {
    this.dataService.selectAll();
    this.injector.get<DataService>(CategoryService.TOKEN).selectAll();
  }

}
...