angularimagesrc

Image is not appearing on view screen - Angular project


I have a page to display the "Beer" information on my Angular project. I receive the Beer information on the route snapshot, it's working. Then I get the name of the beer's image and access an API to get the image. Everything works, but in the html, all fields appears, only the image doesn't.

I have the same code on the form and there the image appears. What I'm doing wrong?

Here's the code for the component:

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  NO_ERRORS_SCHEMA,
  OnInit
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatSidenavModule } from '@angular/material/sidenav';
import { ActivatedRoute } from '@angular/router';
import { MatListModule } from '@angular/material/list';

import { Beer } from '../../model/beer';
import { CommonModule, Location, NgFor, NgIf } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { StartComponent } from '../../shared/components/star-rating/star-rating.component';
import { FileUploadService } from '../../services/file-upload.service';

@Component({
  selector: 'app-beer-view',
  templateUrl: './beer-view.component.html',
  styleUrls: ['./beer-view.component.scss'],
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    NgIf,
    NgFor,
    MatSidenavModule,
    MatButtonModule,
    MatListModule,
    MatCardModule,
    MatToolbarModule,
    MatDividerModule,
    MatIconModule,
    StartComponent,
    CommonModule
  ],
  schemas: [NO_ERRORS_SCHEMA]
})
export class BeerViewComponent implements OnInit {
  beer!: Beer;
  fileName? = '';
  imageShow: any;
  isImageLoading: boolean = true;

  constructor(
    private route: ActivatedRoute,
    private changeDetectorRef: ChangeDetectorRef,
    private location: Location,
    private uploadService: FileUploadService) { }

  ngOnInit() {
    this.beer = this.route.snapshot.data['beer'];
    this.fileName = this.beer.image;
    this.obtainImage();
  }

  onCancel() {
    this.location.back();
  }

  obtainImage(): void {
   console.log("obtain image");
   console.log(this.fileName);
    this.isImageLoading = true;
    this.uploadService.getFile(this.fileName).subscribe(
      (data) => {
        this.createImageFromBlob(data);
        console.log("ok");
        this.isImageLoading = false;
        console.log(this.isImageLoading);
      },
      (error) => {
        console.log("erro");
        this.isImageLoading = false;
        console.log(error);
      }
    );
  }

  createImageFromBlob(image: Blob) {
    let reader = new FileReader();
    reader.addEventListener(
      'load',
      () => {
        this.imageShow = reader.result;
        console.log(this.imageShow);
      },
      false
    );

    if (image) {
      reader.readAsDataURL(image);
    }
  }
}

Here is the code for the view component:

<mat-card appearance="outlined">

  <mat-toolbar color="primary">
    <h1>Beers Detail</h1>
  </mat-toolbar>

  <mat-table class="mat-elevation-z8">
    <mat-list>
      <mat-list-item><b>NAME : </b>{{ beer.name }}</mat-list-item>
      <mat-divider></mat-divider>
      <mat-list-item><b>TYPE :</b> {{ beer.type }}</mat-list-item>
      <mat-divider></mat-divider>
      <mat-list-item><b>ORIGIN :</b> {{ beer.origin }}</mat-list-item>
      <mat-divider></mat-divider>
      <mat-list-item
        ><b>PRICE :</b>
        {{ beer.price | currency : "EUR" : "symbol" : "1.2-2" }}</mat-list-item
      >
      <mat-divider></mat-divider>
      <mat-list-item><b>RATING :</b> {{ beer.rating }} </mat-list-item>
      <mat-divider></mat-divider>
      <mat-list-item *ngIf="!isImageLoading">
        <img [src]="imageShow" alt="Beer Image">
      </mat-list-item>
      <mat-divider></mat-divider>
    </mat-list>

    <mat-card-actions class="actions-center">
      <button
        mat-raised-button
        (click)="onCancel()"
        class="btn-space"
        type="button" >
        <mat-icon aria-hidden="false" fontIcon="keyboard_arrow_left"></mat-icon>
        Back
      </button>
    </mat-card-actions>
  </mat-table>
</mat-card>

The screen:

enter image description here

I have add some log, and I can see that I have got the image ok:

enter image description here

It's working on the form page:

enter image description here

I already tried with a fix URL, and it works. I don't know why the image does not appear.

I have tried to put it outside the <mat-card>, I deleted everything but the line:

<img [src]="imageShow" alt="Beer Image">

I tried:

<img src="{{'data:image/jpg;base64,' + imageShow}}" />
<img src="{{ image_path }}" />

But it doesn't work.

Thanks!


Solution

  • Since you're using OnPush change detection, you need to call change detection manually after assigning the image:

    this.imageShow = reader.result;
    this.changeDetectorRef.markForCheck();
    

    also, you should sanitize image src with DomSanitizer

    this.imageShow = this.sanitizer.bypassSecurityTrustResourceUrl(reader.result);