Home > Enterprise >  Pipe returns blank even though the console prints out correct data
Pipe returns blank even though the console prints out correct data

Time:08-15

On initialisation I retrieve all data from API, so the benefit object gets filled out with data. After that I call another API to get the image data, and fill out the corresponding object with correct base64 data. So the DOM is written when I try to run this Pipe. And even though console.log(base64data); prints correct data, it does not show up in DOM. It is always <img _ngcontent-ple-c114="" src=""> in my application. So I know the first API-calls is correct because the Pipe returns correct base64 string....but it does not set it to src in Benefits.component.html.

Why does it not update the Benefits.component.html?

Benefits.component.html

<div  *ngFor="let benefit of benefits">
 <div >
  <img [src]="benefit.logofile_base64 | returnBase64FromBlob" >
 </div>
</div>

Benefits.pipe.ts

@Pipe({
  name: 'returnBase64FromBlob'
})
export class ReturnBase64FromBlob implements PipeTransform {
  constructor() { }
  transform(value: any ): string {
    if (!value)
      return "";
    var reader = new FileReader();
    reader.readAsDataURL(value);
    reader.onloadend = function () {
      var base64data = reader.result;
      console.log("base64data - crmpipe");
      console.log(base64data);
      return base64data;
    }
    return "";
  }
}

Result in DOM:

<img _ngcontent-ple-c114="" src="">

Edit: Just to ellobarate. The pipe runs two times, first time the console.log(base64data) returns blank, because value is blank. But second time the console.log returns correct data.

CodePudding user response:

Even though you define the onloadend function and its callback fires, the pipe is always returning an empty string.

There may be a better way to accomplish this, but the first thing that comes to mind is to return a promise or an observable that fires when the onloadend event occurs.

I think something like this would work:

  transform(value: any ): string {
    if (!value)
      return of('');

    const reader = new FileReader();
    reader.readAsDataURL(value);
    reader.onloadend = function () {
      return reader.result;
    }
    return fromEvent(reader, 'loadend');

Then in template, you must use async pipe:

<img [src]="benefit.logofile_base64 | returnBase64FromBlob | async" >

CodePudding user response:

@BizzyBob helped me a lot and I will give him correct answer.

But I had to do some adoptions, and wanted to share them:

@Pipe({
  name: 'returnBase64FromBlob',
  pure: true,
})
export class ReturnBase64FromBlob implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) { }
  transform(value: Blob): any {
    if (!value)
      return of("");
    const reader = new FileReader();
    reader.readAsDataURL(value);
    reader.onloadend = function () {
      return reader.result;
    }
    return fromEvent<ProgressEvent>(reader, 'loadend')
      .pipe(
        map(e => {
          const targetImg = (e.target as FileReader | null);
          if (targetImg?.result) {
            return this.sanitizer.bypassSecurityTrustUrl(targetImg?.result.toString());
          } else {
            return "";
          }
        }
        )
      );

  }
}

Now it is solved.

  • Related