This is my first time making my own observable, and i'm not sure if i'm doing it right because the data doesn't show when loaded, i see it in the console but the component doesn't refresh...
I retrieve the ids of my accounts and I make a request to retrieve the accounts then I would like to create an observable of Account [] from the table I just created
account service:
getListFriendsNoConfirmation(): Observable<Account []> {
return this.itSMe().pipe(
switchMap((me: Account) => {
return this.post('account/friendNoConfirmation', HelperAccount.toUpdatePayload(me))
}),
switchMap((resp: ApiResponse)=>{
if(resp != null){
let nofriends: Account [] = [];
let ids= resp.data as number [];
ids.forEach((id:number)=>{
this.getOneAccount(id).subscribe((account: Account)=>{
nofriends.push(account);
})
})
return of(nofriends);
}else{
return []
}
})
)
}
getOneAccount(id: number): Observable<Account>{
return this.getWithName('account/one/',id.toString()).pipe(
map((resp: ApiResponse)=>{
return HelperAccount.fromDtoToAccount(resp.data as AccountDto);
})
)
}
component.ts:
ngOnInit(): void {
this.accountService.getListFriendsNoConfirmation().subscribe((accounts: Account [])=>{
this.nofriends$ = accounts;
console.log(accounts);
})
}
CodePudding user response:
there are a few problems, first, you are not returning an observable if resp
is null. It should be else{ return of([]); }
second, you should never do a subscribe when chining the observables, this doesn't work. use forkjoin instead:
switchMap((resp: ApiResponse)=>{
if(resp?.data === null || resp?.data === undefined || resp.data.length === 0){
return of([]);
}
const nofriends$: Observable<Account>[] = (resp.data as number[]).map(
id => this.getOneAccount(id)
);
return forkJoin(nofriends$);
)}
and maybe your last problem is in component.ts when you do this.nofriends$ = accounts;
. At this point accounts is an array of account, and not an observable.
so it should be:
public nofriends: Account[] = null;
ngOnInit(): void {
this.accountService.getListFriendsNoConfirmation().subscribe((accounts: Account [])=>{
this.nofriends = accounts;
console.log(accounts);
})
}
or if you want
public nofriends$: Observable<Account[]> = this.accountService.getListFriendsNoConfirmation().pipe(
tap(accounts => {console.log(accounts)})
);
and then you subscribe to nofriends$ in the HTML using an async pipe
CodePudding user response:
Your switchMap
is messy as you are returning empty array and then pushing items to it somewhere in the future. This not only makes your code less predictable, but also prevents angular from detecting changes of that array (and this is what you probably see). Also you are returning array []
in else
block instead of observable
which will simply break switchMap
.
Use forkJoin
to build your array
getListFriendsNoConfirmation(): Observable<Account []> {
return this.itSMe().pipe(
switchMap((me: Account) => {
return this.post('account/friendNoConfirmation', HelperAccount.toUpdatePayload(me))
}),
switchMap((resp: ApiResponse)=>{
if(resp != null){
let ids= resp.data as number [];
// if does not work, spread it first with forkJoin(...ids.map())
return forkJoin(ids.map((id:number)=>this.getOneAccount(id)))
}else{
return of([])
}
})
)
}
//useage
getListFriendsNoConfirmation().subscribe((acc:Account[])=>console.log(acc));
This way your pipeline will return alredy initialized array of accounts as forkJoin
block the pipeline until all observables passed to it completes.
Also remember that you always need to subscribe, otherwise pipeline will not be triggered.