0

I have a function in which I create a FileReader and assign callback functions to load and error handlers

handleFileSelect(files:ArrayLike<File>):FileReader|null{
    console.log("got file upload event: ");
    console.log(" image attachment count: ",this.currentImageAttachmentCount);
    if(this.currentImageAttachmentCount >= this.maxImageAttachmentCount)
    {
      console.log("reached max attachment size");
      this.showDialog("You can't attach more files",new DialogContext("",""));
      return null;
    }
    console.log("files selected:",files);
    console.log("total selected: ",files.length);
    for(let i=0;i<files.length;i++)
    {
      console.log("files name:",files[i].name);
      console.log("files object:",files[i])
    }

    //working with only 1 file at the moment
    let file = files[0];
    console.log("file at index 0 ",file);
    if (files && file) {
      console.log("reading file");
      /*
      The FileReader object lets web applications ASYNCHRONOUSLY read the contents of files (or raw data buffers) stored on the user's computer,
      using File or Blob objects to specify the file or data to read.
       */
      let reader:FileReader = new FileReader();

      /*load/onload will be called when the read operation successfully completes.

       */

      //TODOM - Why if I don't bind this then in unit testing, the 'this' of handleReaderLoaded seem to be different fromm the component!!
      reader.onload = this.handleReaderLoaded.bind(this);
      reader.onerror = this.handleFileLoadError.bind(this);
      reader.onloadend = this.debugPrintFileEvents;//TODOM - remove these or make them more useful
      reader.onloadstart = this.debugPrintFileEvents;
      reader.onprogress = this.debugPrintFileEvents;
      reader.onabort = this.debugPrintFileEvents;

      //The readAsBinaryString method is used to start reading the contents of the specified Blob or File.
      reader.readAsDataURL(file);
      this.currentImageAttachmentCount++;
      return reader;
    } else{
      return null;
    }

  }

I am calling newPracticeQuestionComponent.handleFileSelect in the following unit test which will in turn call handleReaderLoaded.

fit('should call error handler when file doesn\'t get loaded successfully', () => {
    let newComponent = component;
    console.log("component is ",newPracticeQuestionComponent);

    let file1 = new File(["dd"], "file1",{type:'image/png',
    endings:'transparent'});


    let reader = newComponent.handleFileSelect([file1]);
    expect(reader).toBeTruthy();
    expect(reader.onerror.name).toEqual(newComponent.handleFileLoadError.name);

  });

I noticed that if I don't use bind(this) in

  reader.onload = this.handleReaderLoaded.bind(this);
  reader.onerror = this.handleFileLoadError.bind(this);

then my callbacks don't work correctly. For example, the handleFileSelect is in NewComponent class. The class also has the following variable

@ViewChild("thumbnailContainer",{read:ViewContainerRef})
  thumbnailContainerRef:ViewContainerRef;

handleFileSelect uses thumbnailContainerRef. Without the bind(this), the thumbnailContainerRef is undefined but with bind(this), thumbnailContainerRef is defined

Why do I need to do

reader.onload = this.handleReaderLoaded.bind(this);
      reader.onerror = this.handleFileLoadError.bind(this);

and can't just do

reader.onload = this.handleReaderLoaded;
      reader.onerror = this.handleFileLoadError;

I thought that as the methods are defined inside the component class, this will always map to the component class.

Manu Chadha
  • 11,886
  • 11
  • 51
  • 115

0 Answers0