1

In our component, we have an upload form, and a confirm message.

file-form.component.html

<div class="tab-pane active" id="upload">
    <div id="loader-wrapper" *ngIf="isUploadLoaderVisible">
        <div id="loader"></div>
        <p class="text-center">Uploading</p>
    </div>
    <div *ngIf="!isFileSubmitted">
        <form class="form-horizontal" [formGroup]="fileUploadForm" (ngSubmit)="onSubmit()">
        <input type="file" id="file" formControlName="file" (change)="fileChangeEvent($event)">
        </form>
    </div>
    <div *ngIf="isFileSubmitted">
        <p class="alert alert-success">
            <i class="fa fa-check"></i>
            Thanks for upload. 
        </p>
        <p><a class="btn btn-default" [routerLink]="['..']">Back</a></p>
    </div>
</div>

file-form.component.ts

import { Component, OnInit, Inject } from '@angular/core';
import {
  FormGroup,
  Validators,
  FormBuilder,
  FormControl
} from '@angular/forms';
import { AngularFire, FirebaseApp } from 'angularfire2';

@Component({
  selector: 'app-file-form',
  templateUrl: './file-form.component.html',
  styleUrls: ['./file-form.component.css']
})
export class SfFileFormComponent implements OnInit {
  // States togglers
  isFileSubmitted: boolean = false;
  isUploadLoaderVisible: boolean = false;

  // Declarations
  fileUploadForm: FormGroup;
  uploadedFile;
  isFileValid: boolean = false;
  uploadedCorrectedFilename: string;

  constructor(private formBuilder: FormBuilder,
    public af: AngularFire,
    @Inject(FirebaseApp) private firebaseApp: firebase.app.App) { }

  ngOnInit() {
    this.initForm();
  }

  private initForm() {
    let file = '';

    this.fileUploadForm = this.formBuilder.group({
      file: file
    });
  }

  fileChangeEvent(fileInput: any) {
    this.uploadedFile = fileInput.target.files;
    let fileType: string = _.toLower(this.uploadedFile[0].type);

    if ( fileType === 'application/pdf' ) {
      this.isFileValid = true;
      console.log('File is valid. Click to upload file', this.uploadedFile[0]);
    } else {
       this.isFileValid = false;
       this.fileUploadForm.reset();
       console.log('File is invalid. Cancel Upload and block form submission', this.uploadedFile[0]);
    }
  }

  onSubmit() {
    if (this.uploadedFile.length === 1) {
      let file: FileList = this.uploadedFile[0];
      console.log('Uploading File', file);

      this.isUploadLoaderVisible = true;

      // Upload to Firebase
      this.firebaseApp
        .storage()
        .ref()
        .child('filesdummy/' + file.name)
          .put(file)
            .then((snapshot) => {
              console.log('Uploaded a blob or file!');

              this.isUploadLoaderVisible = false;
              this.isFileSubmitted = true;
              console.log('isFileSubmitted',this.isFileSubmitted);
              console.log('isUploadLoaderVisible', this.isUploadLoaderVisible);
            });
    }
  }

}

At form submit, we set our triggers boolean to display the loader. It works perfectly and instantaneously.

The code then submit the file (to firebase in our case) and when the promise resolves, I change the loader isUploadLoaderVisible to false and confirmation message one isFileSubmitted to true.

The upload works and in console, I can see booleans where changed correctly and immediately:

Uploaded a blob or file!

isFileSubmitted true

isUploadLoaderVisible false

But on browser (I use Chrome), the view is not "switched" and the ngIf seems to actually see the isFileSubmitted is now true only if i change window/tab and come back or after a very big delay (30-34 sec). Such as the new boolean value of my triggers where not "passed" to the component before a long time...

Maybe it's because I change the boolean states directly from the then() promise result? I don't see how to change the booleans in a different way than I did.

Note: The delay can't be cause by uploading time. Since the promise wouldn't be resolve until upload finish, I wouldn't see the Uploaded console log. And my test file is currently 50kb.

Do you have any idea?

BlackHoleGalaxy
  • 9,160
  • 17
  • 59
  • 103

1 Answers1

2
import { Component, OnInit, Inject, ChangeDetectorRef } from '@angular/core';

export class SfFileFormComponent implements OnInit {
    constructor(private formBuilder: FormBuilder,
        public af: AngularFire,
        @Inject(FirebaseApp) private firebaseApp: firebase.app.App, 
        private ref: ChangeDetectorRef ) { }
    }

    onSubmit() {
        if (this.uploadedFile.length === 1) {
          let file: FileList = this.uploadedFile[0];
          console.log('Uploading File', file);

          this.isUploadLoaderVisible = true;

          // Upload to Firebase
          this.firebaseApp
            .storage()
            .ref()
            .child('filesdummy/' + file.name)
              .put(file)
                .then((snapshot) => {
                  console.log('Uploaded a blob or file!');

                  this.isUploadLoaderVisible = false;
                  this.isFileSubmitted = true;
                  this.ref.detectChanges();
                  console.log('isFileSubmitted',this.isFileSubmitted);
                  console.log('isUploadLoaderVisible', this.isUploadLoaderVisible);
                });
        }
    }

}

Here is a good answer: triggering-angular2-change-detection-manually

More info here: ChangeDetectorRef

Community
  • 1
  • 1
Radu Lucut
  • 132
  • 2
  • 9