传递服务作为Angular2中的输入

JME*_*JME 5 angular

我想创建一个通用的列表组件,其中包含一些我希望所有列表都具有的功能。理想情况下,我想使用不同的服务作为组件的输入以呈现不同的数据集。角度2有可能吗?

从Angular 2文档修改示例

@Component({
    selector: 'Generic List',
    template: 
    `
    <h2>Items</h2>
    <ul class="items">
      <li *ngFor="let item of items"
          [class.selected]="isSelected(item)"
          (click)="onSelect(item)">
        <span class="badge">{{item.id}}</span> {{item.name}}
      </li>
    </ul>
    `
})
export class GTComponent {
    @Input() someService: Service;

     items: Item[];
     private selectedId: number;

    isSelected(item: Item) { return item.id === this.selectedId; }

    onSelect(item: Item) {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果可能的话,如果服务具有一些getItems()返回了Promise的函数,我将如何使用服务中的数据填充items数组。

and*_*tor 6

我也有同样的需求,最终我成功地实现了,到目前为止,效果似乎不错。该实现是用Angular 8编写的。

1. 定义服务

@Input将传递给子组件的所有服务都应该有一个名为 的方法getItems(),因此,首先,我创建了一个抽象类,它只包含该方法的定义。这个类实际上只不过是一个通知 Angular 有关getItems()方法的容器:

@Injectable()
export abstract class ItemsService {

  constructor() { }

  /**
   * Returns a list of all items
   */
  abstract getItems(): Observable<Item[]>;

} 
Run Code Online (Sandbox Code Playgroud)

然后,我们可以创建我们的服务 ( ItemsAService, ItemsBService, ItemsCService),它将实现ItemsService,如下所示:

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { ItemsService } from './items.service';
import { Item } from './item';

const ITEMS_A: Item[] = [
  // our items collection
];


@Injectable()
export class ItemsAService implements ItemsService {

  constructor() { }

  getItems(): Observable<Item[]> {
    return of(ITEMS_A);
    // of(ITEMS_A) returns an Observable<Item[]> that emits the array of mock items.
    // in real life, you'll call HttpClient.get<Item[]>() which also returns an Observable<Item[]>:
   // return this.httpClient.get<Item[]>
  }

}
Run Code Online (Sandbox Code Playgroud)

ItemsBService...和 的代码相同ItemsCService

有关为 Angular 服务创建接口的更多信息,请参见此处

2. 父组件

我们的通用列表组件将包含在父组件中。在此父组件中,我们将注入上述服务,如下所示:

import { Component } from '@angular/core';
import { ItemsAService } from './items-a.service';
import { ItemsBService } from './items-b.service';
import { ItemsCService } from './items-c.service';

@Component({
  ...
})

export class AppComponent  {
 
 constructor(
   public itemsAService: ItemsAService,
   public itemsBService: ItemsBService,
   public itemsCService: ItemsCService
 )  { }

}
Run Code Online (Sandbox Code Playgroud)

然后,在模板中,我们有:

<app-generic-list
  name="A"
  [service]="itemsAService"
>
</app-generic-list>

<app-generic-list
  name="B"
  [service]="itemsBService"
>
</app-generic-list>

<app-generic-list
  name="C"
  [service]="itemsCService"
>
</app-generic-list>
Run Code Online (Sandbox Code Playgroud)

3. 通用列表组件

该组件将有一个@Input() service, 类型ItemsService,我们将从挂钩getItems()中的服务调用该方法ngOnInit()

import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { ItemsService } from '../items.service';
import { Item } from '../item';

@Component({
  selector: 'app-generic-list',
  ...
})

export class GenericListComponent implements OnInit, OnDestroy {
   @Input() name: string;
   @Input() service: ItemsService;

  items: Item[];
  subscription: Subscription;


  constructor() { }

  ngOnInit() {
    if (!this.service) return;
    this.subscription = this.service.getItems()
      .subscribe(items => this.items = items);
  }

  // other methods here

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,父组件和子(通用列表)组件将共享相同的服务实例。


完整示例

https://stackblitz.com/edit/angular-mgubup


我很期待知道是否有另一种更优选的方法来实现这一点。

  • @JME 你可以发布所述方法以便我们可以看到你做了什么吗? (2认同)