我有一個 Angular 服務回傳一組“cleaningDuty”物件。在任務物件中,有一個名為“currentCleaner”的嵌套物件,它有一個 id。
[
{
// other cleaningDuty data
currentCleaner: {
id: string;
active: boolean;
};
},
{
// other cleaningDuty data
currentCleaner: {
id: string;
active: boolean;
};
},
{
// other cleaningDuty data
currentCleaner: {
id: string;
active: boolean;
};
}
]
借助currentCleaner.id我想以相同的pipe()方法動態地從 UserService 獲取 currentCleaner 的用戶資料,并將回傳的用戶資料添加到 cleanDuty 物件。那么物件應該是這樣的:
{
// other cleaningDuty data
currentCleaner: {
id: string;
active: boolean;
},
cleanerData: {
name: string;
photoUrl: string;
// other user data
}
},
不幸的是,即使在投入了幾天之后,我也無法讓它發揮作用。我嘗試了幾乎所有的組合forkJoin(),mergeMap()依此類推。我知道目標組件內的嵌套subscribe()方法可以完成作業,但我想撰寫質量最好的代碼。這是我當前的服務方法狀態(它將用戶可觀察而不是值添加到cleaningDuty物件):
getAllForRoommates(flatId: string, userId: string) {
return this.firestore
.collection('flats')
.doc(flatId)
.collection('cleaningDuties')
.valueChanges()
.pipe(
mergeMap((duties) => {
let currentCleaners = duties.map((duty) =>
this.userService.getPublicUserById(duty.currentCleaner.id),
);
return forkJoin([currentCleaners]).pipe(
map((users) => {
console.log(users);
duties.forEach((duty, i) => {
console.log(duty);
duty.cleanerInfos = users[i];
});
return duties;
}),
);
}),
);
}
getPublicUserById()方法:
getPublicUserById(id: string) {
return this.firestore.collection('publicUsers').doc(id).valueChanges();
}
任何幫助將不勝感激!
uj5u.com熱心網友回復:
forkJoin函式將:
等待 Observables 完成,然后組合它們發出的最后一個值;如果傳遞了一個空陣列,則立即完成。
因此,您必須確保所有內部 Observable 都已完成,然后forkJoin將發出組合值,您可以使用take(1)運算子來實作,如下所示:
getAllForRoommates(flatId: string, userId: string) {
return this.firestore
.collection('flats')
.doc(flatId)
.collection('cleaningDuties')
.valueChanges()
.pipe(
mergeMap((duties) =>
// The `forkJoin` will emit its value only after all inner observables have been completed.
forkJoin(
duties.map((duty) =>
// For each duty, fetch the cleanerData, and append the result to the duty itself:
this.userService.getPublicUserById(duty.currentCleaner.id).pipe(
take(1), // to complete the sub observable after getting the value from it.
map((cleanerData) => ({ ...duty, cleanerData }))
)
)
)
)
);
}
uj5u.com熱心網友回復:
- 檢查您是否需要
switchMap或mergeMap. IMO 我會在valueChanges()發射時取消現有的 observable。請參閱此處了解它們的區別。 - 使用
Array#mapRxJSforkJoin函式來并行觸發請求。 - 使用具有解構語法的RxJS
map運算子向現有物件添加其他屬性。 - 應該使用理想定義的型別而不是
any型別。
嘗試以下
getAllForRoommates(flatId: string, userId: string) {
return this.firestore
.collection('flats')
.doc(flatId)
.collection('cleaningDuties')
.valueChanges()
.pipe(
switchMap((duties: any) =>
forkJoin(
duties.map((duty: any) => // <-- `Array#map` method
this.userService.getPublicUserById(duty.currentCleaner.id).pipe(
map((data: any) => ({ // <-- RxJS `map` operator
...duty, // <-- the `currentCleaner` property
cleanerData: data // <-- new `cleanerData` property
}))
)
)
)
)
);
}
uj5u.com熱心網友回復:
首先,我建議您改進應用程式的型別,這將幫助您更清楚地看到問題。對于我的回答,我假設您定義了 3 個介面 CurrentCleaner、CleanerData 和 RoomData,它們只是:
interface RoomData {
currentCleaner: CurrentCleaner
cleanerData: CleanerData
}
然后你可以撰寫一個輔助函式來從當前的清潔工那里檢索房間資料:
getRoomData$(currentCleaner: CurrentCleaner): Observable<RoomData> {
return this.userService.getPublicUserById(currentCleaner.id).pipe(
map(cleanerData => ({ currentCleaner, cleanerData }))
)
}
如您所見,此函式獲取當前清理器,為其獲取清理器資料并將其映射到 RoomData 物件。
下一步是定義您的主要功能
getAllForRoommates(flatId: string, userId: string): Observable<RoomData[]> {
return this.firestore
.collection('flats')
.doc(flatId)
.collection('cleaningDuties')
.valueChanges()
.pipe(
mergeMap((duties) => {
// here we map all duties to observables of roomData
let roomsData: Observable<RoomData>[] = duties.map(duty => this.getRoomData$(duty.currentCleaner));
// and use the forkJoin to convert Observable<RoomData>[] to Observable<RoomData[]>
return forkJoin(roomsData)
}),
);
}
我認為這種方式很容易理解代碼在做什么。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/437999.html
標籤:javascript 有角度的 谷歌云火库 rxjs 可观察的
