Search code examples
javascriptasynchronoustypescriptangularplunker

Angular 2 UI not updating when items added to array on image.onload()


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);
    }
}

Solution

  • 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