Reputation: 27
I have the following problem:
I want to make a table with entries (Obj). And some of them have a file attribute. If they have a file attribute (entry.file) I want to make a backend call to get the url of that file:
public getFileURL(archiveID: string, documentID: string, sysID: string){
const request: FileRequest = {
archiveID: archiveID,
documentID: documentID,
sysID: sysID
};
this.fileService.file(request).subscribe(response => {
if (response) {
return response;
}
})
}
This is called like: getFileURL(entry.file.archiveID, entry.file.documentID, entry.file.sysID) And it should return an Observable, so I can check if i got a backend response.
<tr *ngFor="let entry of period.claims; let i = index">
...
<td>
<div *ngIf="entry.file">
<div *ngIf="fileClientService.getFileURL(entry.file.archiveID, entry.file.documentID, entry.file.sysID) | async as file; else loading">
<a target="about:blank" class="download" (click)="clickLink(file)"></a>
</div>
<ng-template #loading let-file>loading..</ng-template>
</div>
</td>
All I want is to display "loading" until the url is loaded and then display the a-tag. Also, the url parameter coming back from the backend could be empty. So i also need to display nothing if the url is empty (""). At the moment it fires hundred of backend calls for 2 objects with the entry.file property :(
I am not that good with Observables and I hope someone can help me with that. Thank you so far :)
Upvotes: 0
Views: 336
Reputation: 1132
You need to return Observable directly from your method and map your period.claims
into one Observable:
// add proper type
entries: Observable<...> = getEntries();
getEntries() {
// we map every claim to Observable returned from getFileURL method
const entries = period.claims.map(entry =>
getFileURL(...).pipe(
// we use map to return whole entry from Observable - not only url
map(url => ({
...entry,
url,
}))
));
// forkJoin will return one Observable with value array when each Observable is completed
return forkJoin(...entries);
}
public getFileURL(archiveID: string, documentID: string, sysID: string): Observable<...> {
const request: FileRequest = {
archiveID: archiveID,
documentID: documentID,
sysID: sysID
};
return this.fileService.file(request).pipe(filter(Boolean));
}
If you want not to pass to template empty response you could use filter operator and pass Boolean as callback. It will return only truthy values. You can read more about it: https://www.learnrxjs.io/learn-rxjs/operators/filtering/filter
You can read also more about forkJoin
: https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin
Note that adding proper type to method would tell you what you're doing wrong ;)
Upvotes: 1