How to organize Angular data service

此生再无相见时 提交于 2019-12-12 09:28:18

问题


I have become slightly confused over Observables, Observers, Subjects, BehaviorSubjects, Services, injections, etc.

I am trying to make a simple finance app. I have a transactions service that grabs the data from a REST server and then provides it to other services that can update it if they need to. I can get the list transactions component (which gets its data from getTransactions())to update with the service, but I don't know how to get the edit component (which gets its data from "getTransaction(id)" to work.

What is the best way to let components play with data from the entire array (read/write access) as well as those that just want to play with a single element of the array?

Here's what I have right now: (I've changed it a ton so it's currently broken, but you can see what I was doing)

export class DataBrokerService {
  public transactions:Transaction[];

  constructor() {}

   ngOnInit(){
   }

  getTransactions(): Observable<Transaction[]>{
    if (needUpdate){
      // Download from REST API, subscribe result to transactions
      this.updateTransactions();
    }
    return of(this.transactions);
  }

  getTransaction(id:number): Observable <Transaction>{
    let transaction:Transaction;
    this.getTransactions().subscribe(txns => transaction = txns.find(txn => txn.id === id))
    });
    return transaction$;
  }

I also made this demo showcasing what I am going for: https://stackblitz.com/edit/angular-stackblitz-demo-dftmn3

This is a followup question from: Get one value from observable array


回答1:


It's a good question. I know it's kind of confusing to work with RxJs at first but when you get the hang of it, it's quite powerful.

What you want can be achieved with BehaviorSubject.

Let's find out what Subject is and move onto BehaviorSubject

Subject: is the equivalent to an EventEmitter, and the only way of multicasting a value or event to multiple Observers

For more info, take a look at here

So, we know that Subject is like an EventEmitter. When someone subscribes to it, whenever you call subject.next(value), every subscriber will get the new value. However, late subscribers (meaning subscribing to the Subject after next method is called) won't get the previous values. This is where BehaviorSubject will come into the scene.

It is just like Subject, but when a new subscriber subscribes to it, it'll emit the previous value. Let's use it in your code.

export class DataBrokerService {
    // do not expose your subject to other classes
    private _transactions$: BehaviorSubject<Transaction[]> = new BehaviorSubject([]);
    // instead provide it as an observable
    public readonly transactions: Observable<Transaction[]> = this._transactions$.asObservable();

    needUpdate = true;

    constructor(private http: HttpClient) { }

    ngOnInit() {
    }

    // just return the observable
    getTransactions(): Observable<Transaction[]> {
        if (needUpdate) {
            this.updateTransactions();
        }
        return this.transactions;
    }

    // you can iterate over your transactions and filter them,
    // but DO NOT ever subscribe to it within a service. 
    // Otherwise, other classes won't be able to retrieve the value.
    getTransaction(id: number): Observable<Transaction> {
        return this.getTransactions().pipe(
            map(txns => txns.find(txn => txn.id === id))
        );
    }

    // when you need to update the transactions,
    // simply call this method
    updateTransactions() {
        this.http.get('transactions').subscribe(txns => {
            this.needUpdate = false;
            this._transactions$.next(txns);
        });
    }      
}


来源:https://stackoverflow.com/questions/50459815/how-to-organize-angular-data-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!