简体   繁体   中英

Aurelia BindingEngine propertyObserver does not fire

I have an Aurelia file upload controller where I would like to observe the progress property of any object that is added to the array uploadedFiles . First off, my HTML template looks like this:

<input type="file" name="files" files.bind="fileList" multiple change.delegate="fileSelected($event)" />

This is the controller (simplified). The method fileSelected gets fired when the user selects a file.

import {BindingEngine, inject} from 'aurelia-framework';
import {HttpService} from '../../services/http-service';
import {UploadedFile} from '../../models/uploaded-file';

@inject(BindingEngine)
export class FileUploader {
  httpClient: HttpService;
  fileList: FileList;
  uploadedFiles: UploadedFile[];

  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
    this.httpClient = new HttpService();
    this.uploadedFiles = [];
  }

  fileSelected(): void {
    if (this.fileList) {
      // Convert the FileList object into an array of UploadedFile objects because the Aurelia template engine cannot iterate over a 'FileList' object with 'repeat.for'.
      for (let i = 0; i < this.fileList.length; i++) {
        let file = this.fileList.item(i);
        let uploadedFile = new UploadedFile();
        uploadedFile.file = file;

        // Subscribe to changes of the 'progress' property of every UploadedFile.
        uploadedFile.subscription = this.bindingEngine
          .propertyObserver(uploadedFile, 'progress')
          .subscribe((newValue, oldValue) => {
            console.log('Progress changed from ' + oldValue + ' to ' + newValue);
          });

        this.uploadedFiles.push(uploadedFile);

        // Start off the file upload itself.
        this.httpClient.uploadRequest('files', file, uploadedFile.updateProgress)
          .then((httpResponse) => {
            // File uploaded successfully!
          });
      }
    }
  }
}

I do this because the progress update comes from an external event and therefore the binding from the controller back to the template does not work out of the box (because not every object is observed for performance reasons).

Here's the UploadedFile class:

export class UploadedFile {
  file: File;
  uploaded: boolean;
  totalBytes: number;
  uploadedBytes: number;
  progress: number;
  subscription: any;

  constructor() {
    this.uploaded = false;
    this.progress = 0;
  }

  updateProgress(event: ProgressEvent) {
    this.totalBytes = event.total;
    this.uploadedBytes = event.loaded;

    this.progress = this.uploadedBytes / this.totalBytes * 100;
    console.log('Progress is ' + this.progress + ' %.');
  }
}

Here's what the upload request looks like (note the withProgressCallback line):

import {HttpClient} from 'aurelia-http-client';

export class HttpService {
  backendUrl: string;
  httpClient: HttpClient;

  constructor() {
    // ...
  }

  uploadRequest(url: string, file: File, progressCallback: any): Promise<any> {
    let formData = new FormData();
    formData.append('file', file);

    return this.httpClient.createRequest(url)
      .asPost()
      .withContent(formData)
      .withCredentials(true)
      .withProgressCallback(progressCallback) // This adds the progress callback.
      .send();
  }
}

Now there is obviously something I'm doing wrong, because the property change event never fires, even though I can see the progress updates in the browser console in the UploadedFile class.

Can someone tell me what's wrong with the propertyObserver subscription?

When it comes to upload progress, you need to ensure it's trackable by browser. Secondly, your uploadRequest in HttpService doesn't preserve execution context, which means updateProgress won't be called on correct instances of UploadedFile class. Probably you need to do something like this:

this.httpClient.uploadRequest('files', file, () => uploadedFile.updateProgress() })
      .then((httpResponse) => {
        // File uploaded successfully!
      });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM