I am trying to display images from a list of browser File objects. The template has a table with the the following tr
element in it:
<tr *ngFor="let file of files">
<td>{{ file.name }}</td>
<td>{{ file.type }}</td>
<td>{{ file.size | number }}</td>
<td>
<ng-container *ngIf="getFile(file) | async as dataURL">
<img src="{{ dataURL }}">
</ng-container>
</td>
<td>
<button type="button" mat-button (click)="clickRemove(file)">Remove</button>
</td>
</tr>
In the component, the getFile()
function returns a simple Observable like this:
getFile(file: File): Observable<string> {
console.log('getFile called for a new Observable', file.name);
const obs = new Observable<string>(
subscriber => {
const reader = new FileReader();
console.log('getFile got subscribed to!');
reader.addEventListener("load", ev => {
console.log('getFile got the load event!', reader.result?.slice(0,200));
subscriber.next(reader.result as string);
});
reader.readAsDataURL(file);
}
)
return obs;
}
The intent is that when the Observable is subscribed to, it will go read the data blob represented by the File, then return a string as a data URL for the img
element to display. The console.log
statements show that 1) it is getting subscribed to, 2) it gets the event from the FileReader
then the result is returned in the subscriber.next()
call.
What happens is that this loops indefinitely. Even with one row in the table I get infinitely repeated calls to getFile()
for the same File, then a subscription to the returned Observable, then the file gets read again and a new DataURL returned.
Can anyone help me out by pointing out where the loop is? I suspect the problem is that the Angular's change detection logic is doing this, but I don't have any idea of how to diagnose that or fix it if that is the case.
Any help appreciated.