JavaScript multiple object instances, cannot correctly access properties inside event handler
I have a working version of HTML5 drag & drop file uploader. I was editing the JS code to support multiple file uploads on same page. I came across with a problem by trying to access "instance" properties in methods which are registered as events.
The problem is shown by the code below, in method this.drop
.
The reason of existence of the this.$$upload_self
property is to access data through this property. For example, I can't use this
keyword inside this.drop
function, because when event is raised, this
not referring my "instance".
I'm not sure that by creating $$upload_self
was a good idea.
The new instances area created like this:
var recording_upload = new upload();
recording_upload.init(recording_upload, ...);
Code of Drag & drop file upload:
var upload = function() {
this.$$upload_self = null;
this.$drop = null;
this.$status = null;
this.$progress = null;
this.maxNumberOfFiles = null;
...
this.init = function (self, pUrl, maxNmbOfFiles, dropArea, progress, status) {
$$upload_self = self;
$$upload_self.postUrl = pUrl;
$$upload_self.maxNumberOfFiles = maxNmbOfFiles;
$$upload_self.$drop = $("#" + dropArea);
$$upload_self.$progress = $("#" + progress);
$$upload_self.$status = $("#" + status);
$$upload_self.$drop.bind('dragenter', $$upload_self.enter);
$$upload_self.$drop.bind('dragleave', $$upload_self.leave);
$$upload_self.$drop.bind('drop', $$upload_self.drop);
};
this.enter = function (e) {
$(e.target).addClass('hover');
return false;
};
this.leave = function (e) {
$(e.target).removeClass('hover');
return false;
};
this.drop = function (e, _this) {
$(e.target).removeClass('hover');
var files = e.originalEvent.dataTransfer.files;
if (files.length > $$upload_self.maxNumberOfFiles) { // for example, here $$upload_self references always last instance...
$$upload_self.di开发者_运维知识库splayErrorMessage('Error: You can only drop ' + $$upload_self.maxNumberOfFiles + ' file(s) at time.');
return false;
}
...
};
...
}
Is there any workaround to solve this issue? I believe this maybe a common problem, but can't find nothing to solve this problem.
Any help is very much appreciated.
You could ditch the new
keyword altogether and use a fresh closure for each instance of upload
.
EDIT: Updated to avoid potential clobbering of global this
.
var upload = function(pUrl, maxNmbOfFiles, dropArea, progress, status) {
return {
postUrl: pUrl,
...
drop: function(e) {
...
if (files.length > this.maxNumberOfFiles) {
this.displayErrorMessage(...);
}
...
},
...
};
};
...
var someUpload = upload(...);
Try to search for a "scope". As an example see how it implemented in ExtJS.
In a modern browser you can do this:
$$upload_self.$drop.bind('dragleave', $$upload_self.leave.bind($$upload_self));
For older IE versions you can do this:
$$upload_self.$drop.bind('dragleave', function() { $$upload_self.leave(); });
Really the ".bind()" method of all Function objects in new browsers just creates a little intermediate function for you, essentially like the second example. The Mozilla docs page for ".bind()" has a very good block of code you can use as a "polyfill" patch for browsers that don't support ".bind()" natively.
精彩评论