I'm trying to remove duplicate JavaScript code. I have a page with many <input type="file">
. Each loads an image and performs some distinct processing. The problem is that I have many duplicates of the following code:
inputFile1.onchange = function (e) {
var file = e.target.files[0];
if (typeof file == 'undefined' || file == null) {
return;
}
var imageType = /image.*/;
if (!file.type.match(imageType)) {
window.alert('Bad file type!');
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var imageLoader = new Image();
imageLoader.onload = function () {
// process image
};
imageLoader.src = e.target.result;
};
reader.readAsDataURL(file);
};
inputFile2.onchange = ... (repeats all but process image)
inputFile3.onchange = ... (repeats all but process image)
Only the code at process image
comment varies. How can I remove the surrounding duplicate code?
I know that JavaScript functions are objects. How can I define a function object and create one distinct instance for each event handler, passing a different function for process image
to each object?
You can make a generator for such functions with a closure taking the individual callback as an argument:
function getChangeHandler(loadCallback) {
return function (e) {
var file = e.target.files[0];
if (typeof file == 'undefined' || file == null) {
return;
}
var imageType = /image.*/;
if (!file.type.match(imageType)) {
window.alert('Bad file type!');
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var imageLoader = new Image();
imageLoader.onload = loadCallback; // <= uses the closure argument
imageLoader.src = e.target.result;
};
reader.readAsDataURL(file);
};
}
inputFile1.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile2.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile3.onchange = getChangeHandler(function() { /* custom process image */ });
An other, eventually superior approach would be to use only one change
-event handler for all inputs, that dynamically chooses the custom image processor by the name
or id
of the input:
var imageProcessors = {
"box1": function() { … },
"anotherbox": function() { … },
…
};
function changeHandler(e) {
var input = this; // === e.target
…
reader.onloadend = function (e) {
…
imageLoader.onload = imageProcessors[input.id];
};
}
// and bind this one function on all inputs (jQuery-style):
$("#box1, #anotherbox, …").click(changeHandler);