Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove duplicate JavaScript code of DOM event handler?

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?

like image 848
fernacolo Avatar asked Apr 19 '26 00:04

fernacolo


1 Answers

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);
like image 198
Bergi Avatar answered Apr 20 '26 14:04

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!