在可观察数组中根据匹配的对象属性替换自定义对象。

huangapple go评论76阅读模式
英文:

Replace custom object in an observable array based on matching object property

问题

我正在获取一个自定义IPix对象的可观察数组(Observable<IPix[]>)从数据库(通过API),然后通过将IPix对象的编辑副本传递回API进行PUT请求(基于legacyConfigTrackerId)来更新数据库中的记录。

我想知道如何用修改后的副本(基于legacyConfigTrackerId)替换当前显示的数组中的原始IPix对象,以便记录的更改将立即反映在表格中,而无需搜索/刷新。

现在我甚至无法弄清楚如何筛选数组,筛选的结果一直返回未定义,然后什么都没有显示:

  pixRecords$!: Observable<IPix[]>;

  updatePix(pix: IPix) {
    console.log('update clicked');

    this.pixRecords$ = 
      this.pixRecords$.pipe(
        map((records: IPix[]) =>
          records.filter((p: IPix) => {
            p.legacyConfigTrackerId !== pix.legacyConfigTrackerId 

            // 需要做一些事情来用 'pix' 参数替换数组中的原始对象
          })
        )
      );

    pix.contract.effectiveDate = this.revertEffDateFormat();
    pix.contract.termDate = this.revertTermDateFormat();
    this.pixService.putPix(pix);
    this.formattedEffDate = '';
    this.formattedTermDate = '';
    this.closeModal.next(null);
  }

我对Angular还很新,也许我的方法完全错误,我愿意听取建议。

英文:

So I'm fetching an observable array of custom IPix objects (Observable<IPix[]>) from a db (via an API) and then updating a record in the db by passing an edited copy of the IPix object back to the API in a PUT request (based on legacyConfigTrackerId).

I want to know how to replace the original IPix object in the array currently being displayed with the altered copy (based on legacyConfigTrackerId) so that the changes to the record will be reflected in the table right away without having to search/refresh.

Right now I can't even figure out how to filter the array, the result of the filter keeps coming back undefined and then nothing is displayed:

  pixRecords$!: Observable&lt;IPix[]&gt;;

  updatePix(pix: IPix) {
    console.log(&#39;update clicked&#39;);

    this.pixRecords$ = 
      this.pixRecords$.pipe(
        map((records: IPix[]) =&gt;
          records.filter((p: IPix) =&gt; {
            p.legacyConfigTrackerId !== pix.legacyConfigTrackerId 

            // need to do something to replace original object in array with the &#39;pix&#39; argument
          })
        )
      );

    pix.contract.effectiveDate = this.revertEffDateFormat();
    pix.contract.termDate = this.revertTermDateFormat();
    this.pixService.putPix(pix);
    this.formattedEffDate = &#39;&#39;;
    this.formattedTermDate = &#39;&#39;;
    this.closeModal.next(null);
  }

I'm new to Angular so maybe my approach is all wrong, I'm open to suggestions.

答案1

得分: 0

当您使用Observables时,值会被发射然后消失。您不能像对待其他变量一样对待保存Observable的变量。您不应该将其分配给其他东西(比如这样:this.pixRecords$ = this.pixRecords$.pipe(...))。

相反,您需要采取以下措施之一:

  • 将发射的数据存储在代码中可以使用的数组中。(这通常是最简单的方法。)
  • 或者利用Observables的特性来保留数据并在Observable管道中使用它。

对于第二个选项,有几种方法:

  • 您可以使用scan操作符来保留发射的数据数组并添加/删除/更新数组中的值。
  • 您可以使用BehaviorSubject并将http调用返回的数组发射到BehaviorSubject中,它会保留其最后一次发射的值。

以下是使用scan操作符的示例:

products$ = this.http.get<Product[]>(this.productsUrl)
  .pipe(
    tap(data => console.log('Products: ', JSON.stringify(data))),
    catchError(this.handleError)
  );

private productInsertedSubject = new Subject<Product>();
productInsertedAction$ = this.productInsertedSubject.asObservable();

allProducts$ = merge(
  this.products$,
  this.productInsertedAction$
).pipe(
  scan((acc, value) =>
    (value instanceof Array) ? [...value] : [...acc, value], [] as Product[])
)

在这里,检索到的产品被发射到products$ Observable中。但是UI绑定将是到allProducts Observable。

productInsertedAction 发射任何新添加的产品。addProducts$ Observable会在每次添加新产品时重新发射。

scan操作符会保留先前的产品数组,因此此代码可以引用它(作为acc变量)并对其进行添加操作。

此代码可以扩展以包括更新和删除操作。

您提到您是新手使用Angular。如果您想更深入了解基础知识,我有一个介绍RxJS的视频,您可以在这里找到:https://youtu.be/vtCDRiG__D4

英文:

When you are working with Observables, values are emitted and then gone. You can't treat a variable holding an Observable like other variables. You shouldn't really assign it to something (like this: this.pixRecords$ = this.pixRecords$.pipe(...)).

You instead need to either:

  • Store the emitted data in an array that you work with in the code. (This is often the easiest approach.)
  • Or leverage features of Observables to retain the data and work with it in an Observable pipeline.

For the second option, there are several approaches:

  • You can use the scan operator to retain the emitted array of data and add/remove/update the values in the array.
  • You can use a BehaviorSubject and emit the returned array from the http call into a BehaviorSubject, which retains it's last emission.

Here is an example of using the scan operator:

  products$ = this.http.get&lt;Product[]&gt;(this.productsUrl)
    .pipe(
      tap(data =&gt; console.log(&#39;Products: &#39;, JSON.stringify(data))),
      catchError(this.handleError)
    );

  private productInsertedSubject = new Subject&lt;Product&gt;();
  productInsertedAction$ = this.productInsertedSubject.asObservable();

  allProducts$ = merge(
    this.products$,
    this.productInsertedAction$
  ).pipe(
    scan((acc, value) =&gt;
      (value instanceof Array) ? [...value] : [...acc, value], [] as Product[])
  )

Here the retrieved products are emitted into the products$ Observable. But the UI binding will be to the allProducts Observable.

The productInsertedAction emits any newly added product. The addProducts$ Observable then re-emits any time a new product is added.

The scan operator retains the prior array of products, so this code is able to reference that (as the acc variable) and add to it.

This code could be expanded to include update and delete operations.

You mentioned that you were new to Angular. I have an intro to RxJS video that you can find here if you want to dive a bit deeper into the basics: https://youtu.be/vtCDRiG__D4

huangapple
  • 本文由 发表于 2023年7月7日 06:43:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632936.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定