Angular 2 Firebase Storage – Image preview on upload finish

I’m trying to show the uploaded img after the uploadTask is successful, but because of the asynchronous loading, the view tries to show it before the upload is finished.

This is the method:

upload(value){
    let file = value.target.files[0];
    let storageRef = firebase.storage().ref('noticias/' + file.name);
    let uploadTask = storageRef.put(file);

    uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
      function(snapshot) {
        let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log('Upload is ' + progress + '% done');
        switch (snapshot.state) {
          case firebase.storage.TaskState.PAUSED: // or 'paused'
            console.log('Upload is paused');
            break;
          case firebase.storage.TaskState.RUNNING: // or 'running'
            console.log('Upload is running');
            break;
        }
      }, function(error) {
      switch (error) { 
        case 'storage/unauthorized':
          break;

        case 'storage/canceled':
          break;

        case 'storage/unknown':
          break;
      }
    }, function() {
      // Upload completed successfully, now we can get the download URL
      let downloadURL = uploadTask.snapshot.downloadURL;
      console.log('Upload done!');
    });

    storageRef.getDownloadURL().then(url => this.imgUrl = url);
    this.uploadedImg = true;
  }

And this is the view:

<img *ngIf="uploadedImg" [src]="imgUrl" />

The last two lines of the method are the ones which load way too early. I’ve also tried to move them inside the success function. The problem is that if I move them there, this no longer refers to the class and I can’t change the values in the view.

Answer

Losing reference to this is a common problem in javascript, and there’s a simple pattern to keep track of it. You’re right about moving the lines inside the success function, just do this at the beginning:

upload(value){
    let that = this;
    let file = value.target.files[0];

Now that will always point to the original this, and the following will work as expected:

}, function() {
    // Upload completed successfully, now we can get the download URL
    let downloadURL = uploadTask.snapshot.downloadURL;
    console.log('Upload done!');
    // Using original `this`
    storageRef.getDownloadURL().then(url => that.imgUrl = url);
    that.uploadedImg = true;
});

Leave a Reply

Your email address will not be published. Required fields are marked *