6

I am attempting to add images to an array and display them on the screen. I do not want to display the images until after the browser has loaded them. I have .onload call back specified on the image object and am adding the image to the array within that callback. The UI is only updated when a click event or some other "change event" happens. I looked in to observables but feel like thats a bit overkill for something this simple. I believe in angular 1 there was some sort of $watch that could be done to class properties. This seems trivial... object gets updated, UI should reflect it. Any help is appreciated. Thanks :)

Here is a plunker demonstrating what I am trying to do. I am adding X kittens in the constructor. If that code is removed, the first "Add Kittens" press will not update the UI but subsequent additions of kittens will show previous kittens...

private addItem(itemsArray) { 
    var randomnumber = Math.floor(Math.random() * (500 - 200 + 1)) + 200;  
    var imageObj = new Image();
    imageObj.src = "http://placekitten.com/300/"+randomnumber;

    imageObj.onload = function () {       
        itemsArray.push(imageObj);
    }
}
crizzwald
  • 1,037
  • 2
  • 14
  • 30
  • Here's the same code but with initial call in the constructor commented out. [plunker](http://embed.plnkr.co/shHj0Q7x5QmoyZCosDMx/). I'm also printing the `src` and it seems to be working fine. – Stubbies Jun 23 '16 at 00:36
  • Your plunker doesn't work in Safari 9.1.1. What browser are you using? I believe it's hit or miss in chrome. The first click renders no kittens to the UI and subsequent clicks renders the previous kittens. – crizzwald Jun 23 '16 at 00:39
  • It works all the time in chrome for me, some images are very similar, check the url for a clue. – Stubbies Jun 23 '16 at 00:43
  • Ok cool, I need this to work in Safari as well though :/ thanks for looking into it for me – crizzwald Jun 23 '16 at 00:46

1 Answers1

5

I can't reproduce in the Plunker (with Chrome)

You could try to explicitly invoke change detection

export class App {
  public items: any = []
  constructor(cdRef:ChangeDetectorRef) { // <<<== add parameter
    this.addItems();
  }

  addItems() {
    for(var i = 0; i < 3; i++)
    {
      this.addItem(this.items);
    }
  }

  private addItem(itemsArray) { 
    var randomnumber = Math.floor(Math.random() * (500 - 200 + 1)) + 200;  
    var imageObj = new Image();
    imageObj.src = "http://placekitten.com/300/"+randomnumber;

    imageObj.onload = () => { // <<<== change from function() to () =>     

        itemsArray.push(imageObj);
        this.cdRef.detectChanges(); // <<<== invoke change detection
        //alert("added");
    }
  }
}

My suspicion is that

imageObj.onload = () => {

can't be properly patched on all browsers and if the callback runs outside Angulars zone, it doesn't get notified and doesn't run change detection.

This

imageObj.addEventListener('load', () => {       

might also solve it (and would be the better option if it solves it as well - hard to tell without being able to reproduce - I have no Safari around).

Plunker example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567