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.