簡體   English   中英

角度8:如何為同一組件的多個實例提供不同的服務實例

[英]Angular 8: How to provide different service instances to multiple instances of the same component

我試圖在Angular 8中創建可重復使用的基於d3的儀表板組件。我想創建可以打包到模塊中並可以在不修改組件代碼(甚至沒有構造函數參數)的情況下重用的組件(如條形圖)。 我還希望允許x個顯示不同數據的同級實例。

我有一個正常工作的組件,並且已將其api分解為用於簡單顯示配置的輸入參數和所有組件都需要進行數據/交互的服務接口。 我將服務接口實現為抽象基類,並且組件將基類作為構造函數參數(用戶/開發人員無法修改我的方案中的構造函數參數或任何組件代碼)。

這給我留下了一個問題-如何在不修改組件構造函數參數的情況下為不同的組件實例提供服務基類的不同實現。

我已經嘗試過為條形圖創建一個抽象基類,然后創建派生的條形圖實例,這些實例僅通過采用派生的barchartservice實例而有所不同,但是存在的問題是模板和樣式沒有從組件基類繼承。

export class BarChartComponent implements AfterViewInit
{
    ...

    public constructor(public service: BarChartService) {}

    public ngAfterViewInit() {
        ...

        this.service.dataInit$.subscribe(() => {
            let data = this.service.barChartData;
            this.drawChart(data);
        });

        this.service.dataRefresh$.subscribe(() => {
            let data = this.service.barChartData;
            this.drawChart(data);
        });
    }

    private drawChart(data): void {
        ...
    }
}

@Injectable()
export abstract class BarChartService {

    abstract barChartData: any;

    abstract dataInit$: Observable<boolean>;
    abstract dataRefresh$: Observable<boolean>;

    abstract barChartSelect(string): void;
    abstract barChartXValue: (d: any) => any;
    abstract barChartYValue: (d: any) => any;
}

最終,我只希望可以顯示不同數據的可重用多實例組件。 任何見識將不勝感激。

為了清楚起見,這是barChartService派生類的工作(批准服務參數包含后端訪問邏輯和跨儀表板共享的交叉過濾器):

@Injectable()
export class ApprovalsBarChartService implements BarChartService {

    private init = new Subject<boolean>();
    dataInit$ = this.init.asObservable();

    private refresh = new Subject<boolean>();
    dataRefresh$ = this.refresh.asObservable();

    public get barChartData(): any {
        return this.service.approvalsGroupedByApprover.all();
    }

    public barChartXValue = function (d) { return d.key; };
    public barChartYValue = function (d) { return d.value; };

    public constructor(public service: ApprovalService) {   

        this.service.init$.subscribe(() => {
            this.init.next(true);
        });

        this.service.refresh$.subscribe(() => {
          this.refresh.next(true);
        });
    } 

    public barChartSelect(processor: string): void {
        this.service.approvalsIndexedByApprover.filter(processor);
        this.service.selectedProcessor = processor;
        this.service.selectItems = +this.service.xfilter.groupAll().reduceCount().value();
        this.service.refreshCharts();
    }
}

BarChartService真的需要成為一項服務嗎? 在我看來,如果您不需要在不同組件之間重用同一服務實例,那么您就不需要服務。

因此,您可以在組件的構造函數內部實例化“服務”,而不是注入它。 所以代替:

public constructor(public service: BarChartService) {}

您可以:

public service: BarChartService;
public constructor() {
    this.service = new BarChartService();
}

請注意,由於該類是抽象的,因此您需要實例化具體的子類。

現在,如果您真的想將服務中的不同實例注入到不同的組件中(例如,因為其中一些服務將在某些組件之間共享),則可以為每個實例提供不同的注入令牌,並在其中使用注入令牌組件的構造函數以選擇所需的實例:

聲明兩個注入令牌:

export const MyToken1 = new InjectionToken<BarChartService>('MyToken1');
export const MyToken2 = new InjectionToken<BarChartService>('MyToken2');

為每個令牌分配一個不同的服務實例:

@NgModule(...) 
export class ... {
    ...
    providers: [
        {provide: MyToken1, useValue: new MyServiceInstance(1, 2, 3)},
        {provide: MyToken2, useValue: new MyServiceInstance(4, 5, 6)},
    ]
}

然后在組件中,選擇要注入的服務:

public constructor(@Inject(MyToken1) public service: BarChartService) {}

我最初試圖在這里做的事情是不可能的。

值得慶幸的是,它也沒有必要:

解決方案:不需要服務(BarChartService)。 BarChartService中定義的所有內容都可以並且應該作為@Input參數傳遞,但BarChartSelect除外,BarChartSelect應該是在父項中捕獲的@Output事件,並調用ApprovalService上的方法,該方法本質上是數據檢索服務包含整個儀表板(不特定於組件)的交叉過濾器。 我沒有意識到我們可以將函數作為輸入參數傳遞給組件以自定義行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM