1

I implemented dynamic background-image using angular. This is how I did it:

<div [style.height.px]="coverHeight" [style.background-image]="'url(' + coverImage + ')'" class="card mb-3">
</div>

I did this, because it is a way for resizing images without distortion. That's working fine.

But, below this, there is an input, and every time the (change) function is called, I want the image on the div to update.

So I have a default image, and when my user puts something like https://s.imgur.com/images/logo-1200-630.jpg?2 in the input, the image will show there. That's been easy, as you can see, the background-image is dynamic. But I want to validate if the link exists, if not, the default image will stay there.

So I tried a few things, such as:

Check if image exists on server using JavaScript?
Checking if image does exists using javascript
see if src of img exists

But neither of them works for me the way I need it.
What I need is a function that returns me true if the image exists.

What problems I encountered:

When trying to use new XMLHttpRequest();, I'm getting CORS error from some domains, such as IMGUR.

When trying to use var img = new Image(); and then capturing onerror, it works somewhat, but I still can't return a Boolean, because the onerror function does not return anything of use, the only thing I can get is an alert when the image is invalid.

Trying <div onerror="doSomething()"> does not work either, the function is not called (probably because it is a div, and not an img tag).

The closest I got, is when using

var img = new Image();
img.src = url;

Because that will actually generate an error in the browser's console when the image is invalid. The error is a (not found) GET. But when I tried to try ... catch it, it seems it never counts it as an exception, so it will always go into try.

Also, trying things such as checking the image's width doesn't work either, and I don't really know why. Also, I don't want to use the DOM for this, and this function should be very simple, check the image, return true or false.

This should be easy, but I'm having a hard time... Any ideas?

CH4B
  • 734
  • 1
  • 9
  • 27

2 Answers2

1

With images you have access to events like onload an onError. You can utilize these two for your purpose. At the end I have presented a StackBlitz, but be sure when you test it, Stackblitz only work with https urls.

So when the user inputs something in the input you call a function, yes? That function could then look like:

changeBackground() {
  let img = new Image();
  // imgUrl is the property containing what user has typed in input
  img.src = this.imgUrl;
  img.onload = () => {
    this.coverImage = img.src;
  }
  img.onerror = () => {
    console.log('failed')
  }
}

StackBlitz

AT82
  • 71,416
  • 24
  • 140
  • 167
0

in your component inject the httpClient.

import { HttpClient } from '@angular/common/http';
import { catchError, mergeMap } from 'rxjs/operators';
import { of } from 'rxjs';

constructor(private http: HttpClient) {}

Override your url method:

  url(coverImage: string) {
    const defaultImageUrl =
      'http://mihost.io/default-image';

    return this.http
      .get(coverImage, {
        responseType: 'blob',
      })
      .pipe(
        mergeMap((blob: { size: number; type: string }) => {
          if (blob.type === 'image/png') {
            return of(coverImage);
          } else {
            return of(defaultImageUrl);
          }
        }),
        catchError(error => {
          return of(defaultImageUrl);
        }),
      );
  }

in your html use async pipe.

[style.background-image]="'url(' + coverImage + ')' | async "

in if (blob.type === 'image/png') compare with another types or array of types!

Manuel Panizzo
  • 876
  • 3
  • 8
  • You see, `url()` is not a method. Its just a way for the image to be dynamic. Whenever the variable 'coverImage' changes value, the background-image will change. There's a function on (change) that is supposed to check the field value and validate if the image exists. In case the image does exist, the variable will be updated. If it doesn't, the variable will remain the same – CH4B Sep 11 '19 at 19:04
  • I tried creating a function like the one you suggested. but the return was always a meaningless observable, whichever was the value i'd send as param. – CH4B Sep 11 '19 at 19:05