Angular 使用数据服务集中数据和http调用

Angular 使用数据服务集中数据和http调用,angular,Angular,我已经阅读了很多关于如何使用http客户机在服务中实现http调用的教程,这很好。当我试图在两个不同的服务中分离数据和http调用时,问题就来了,我会因为可观察对象和订阅以及体系结构而感到困惑 请检查以下示例: 1 ListComponent-显示项目列表 1数据服务-用于数据,具有项目列表和获取、添加、更新、删除等功能。 1 HttpService-对于http调用,使用Swagger为Angular自动生成。 我使用DataService作为数据的中心点,以便可以从不同的组件访问数据。当Li

我已经阅读了很多关于如何使用http客户机在服务中实现http调用的教程,这很好。当我试图在两个不同的服务中分离数据和http调用时,问题就来了,我会因为可观察对象和订阅以及体系结构而感到困惑

请检查以下示例:

1 ListComponent-显示项目列表 1数据服务-用于数据,具有项目列表和获取、添加、更新、删除等功能。 1 HttpService-对于http调用,使用Swagger为Angular自动生成。 我使用DataService作为数据的中心点,以便可以从不同的组件访问数据。当ListComponent请求条目列表时,DataService调用http服务从服务器获取数据。http服务中的这个操作是异步的,因此它返回一个可观察的

我使用主题和订阅实现了它:

export class ListComponent implements OnInit, OnDestroy {

  private listChangedSubscription: Subscription;

  ngOnInit() {
    this.list = this.dataService.getList();
    this.listChangedSubscription = this.dataService.listChangedSubject.subscribe(
      (list: Array<Item>) => {
        this.list = list;
    });

  ngOnDestroy() {
    this.entriesChangedSubscription.unsubscribe();
  }

export class DataService {

  listChangedSubject = new Subject<Array<Item>>();

  private list: Array<Item> = [];

  private fetchItems() {
    return this.httpService.getItems().subscribe(
      (list: Array<Item>) => {
        this.list= list;
        this.listChangedSubject.next(this.list.slice());
      }
    );
  }

export class HttpService {

    public getItems(observe?: 'body', reportProgress?: boolean): Observable<Array<Item>>;
    public getItems(observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Array<Item>>>;
    public getItems(observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<Item>>>;
    public getItems(observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
我认为在DataService中使用可观测值或承诺(而不是主题和订阅)可能是一种更好的方法,但我无法让它工作,对fetchData函数有什么建议吗

在所有教程中,我都阅读了直接调用http服务的组件,我认为这仅适用于组件保存其数据且不需要数据服务的简单场景

对此,建议采用什么方法

提前谢谢


Dani

啊,好吧,我想我更能理解, 我认为实现这一点的最好方法仍然是主题数据服务。这就是RXJS最擅长的地方

列出组件模板:

<ul *ngFor="let item of list"> 
  <li (click)="onClick(item)"> 
    <span>{{ item.date } </span>
    <span>{{ item.text }}</span> 
  </li>
</ul>

export class ListComponent implements OnInit {

  list: Item[] = [];

  ngOnInit() {
    this.httpService.getItems().subscribe(val => {
      this.list = val;
    });
  }

  onClick(item: item): void {
    this dataService.updateItemListSubject(item);
    // navigate to route
  } 
}
请注意,您不再需要onDestroy和订阅列表。HttpClient将为您执行此操作

export class DataService {

  private itemSubject = new Subject<Item>();

  getItemSubject(): Observable<Item> {
    return this.itemSubject.asObservable();
  }

  updateItemSubject(item: Observable<Item>): void {
    this.itemSubject.next(item);
  }

}
ItemDetail组件模板

<div>
  {{item$ | async}}
</div>

export class ItemDetail implements OnInit {
  item$: Observable<Item>

  ngOnInit() {
    this.item$ = this.dataService.getItemSubject();
  }
}

export class HttpService {
  // normal stuff
}
抱歉这么久了

让DataService进行Http调用可能会在将来的某个地方变得复杂,并且要求DataService了解更多关于应用程序的信息。这就是为什么我在父组件中进行Http调用,然后将响应分配给DataService中的一个值,如上所示


使用RXJS的优点是,无论您在哪里通过异步管道或订阅使用数据,每次发生更改时都会收到通知。它还可以防止您担心从DataService获取列表时意外地执行列表。2而且它会破坏一切,因为您忘记了列表到处都在使用。

在Angular工作了几年后,我想我可以回答我自己的问题:-

我认为这可能是一个更好的方法,使用可观察到的或承诺 数据服务,而不是主题和订阅,但我没有 为了让它工作起来,对fetchData函数有什么建议吗

在Angular中,在服务中使用Subject是非常常见的,所以您可以发出值,客户端可以订阅。对于后者,通常会添加如下属性或方法:

const itemsSubject = new Subject<any>();

const items$ = itemsSubject.asObservable();

对于数据服务发出http请求的特定情况,可以使用Behavior Subject或ReplaySubject,以便在请求完成后订阅的客户端可以获得以前的响应

在所有教程中,我都阅读了直接调用 http服务,我认为它只对中的简单场景有效 该组件保存其数据,并且不需要数据 服务

对此,建议采用什么方法

角度组件的主要用途是处理视图的显示。一旦获取或处理数据变得复杂,强烈建议将其提取到服务中。这允许更好的组件重用性并提高可测试性

将此作为一般建议,并根据具体情况做出选择

这里有一个可以作为参考的帖子列表:

我还建议阅读Angular和RxJS的官方文档:


如果您编写自己的服务,而不是使用招摇过市或。您可以创建一个通用服务,并在类似于模型的项目上调用它,防止使用任何类型的服务来获得typescript和intellisense的功能。以下是一个例子:

服务:

@Injectable()
export class GenericService {

  constructor(private _http: HttpClient) { }

  get<T>(url: string): Observable<T> {
    return this._http.get<T>(url);
  }
  post<T,U>(url: string, body: U): Observable<T> {
    return this._http.post<T>(url, body);
  }
  put<T,U>(url: string, body: U): Observable<T> {
    return this._http.put<T>(url, body);
  }
  delete<T>(url: string): Observable<T> {
    return this._http.delete<T>(url);
  }
}
组成部分

@Component({
  selector: ''
  ...
  providers: [GenericService]
})
export class ListComponent implements OnInit {

  list: Item[] = [];

  constructor(private _service: GenericService)

  ngOnInit() {
    this._service.get<Item>(url).subscribe(val => {
      this.list = val;
    }
  }
}

通过使用这种方法,您可以删除您的服务文件,在需要调用api的地方,将通用服务注入组件并调用所需的http方法。通过在GenericService中调用httpClient方法上的toPromise,您可以将Observable转换为promise。

我通常更喜欢使用能够访问数据的服务,而不是组件,因此它们之间更容易共享数据。例如,在此应用程序中,onClickitem导航到项目的详细信息,将项目的id作为route param:id传递。我需要在ItemDetail组件中获取此id的项目对象,以便在服务中而不是组件中拥有列表
耳鼻喉科使它更容易。我可以用@Input实现它,但它的元素更少。有什么建议吗?谢谢你的评论!该列表仅用于表示和选择:{{item.date}{{{item.text}}我更新了我的答案,以便更清楚地了解您试图做什么
@Component({
  selector: ''
  ...
  providers: [GenericService]
})
export class ListComponent implements OnInit {

  list: Item[] = [];

  constructor(private _service: GenericService)

  ngOnInit() {
    this._service.get<Item>(url).subscribe(val => {
      this.list = val;
    }
  }
}