英文:
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<IPix[]>;
updatePix(pix: IPix) {
console.log('update clicked');
this.pixRecords$ =
this.pixRecords$.pipe(
map((records: IPix[]) =>
records.filter((p: IPix) => {
p.legacyConfigTrackerId !== pix.legacyConfigTrackerId
// need to do something to replace original object in array with the 'pix' argument
})
)
);
pix.contract.effectiveDate = this.revertEffDateFormat();
pix.contract.termDate = this.revertTermDateFormat();
this.pixService.putPix(pix);
this.formattedEffDate = '';
this.formattedTermDate = '';
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<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[])
)
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论