Sunday, February 1, 2015

JavaScript Closures: Pass parameters to callbacks

Many JavaScript libraries allow to define callbacks. We often need to pass various parameters oder some context from outside to the same callbacks. JavaScript Closures makes it possible. The idea is to define two functions - one outer and one inner which acts as callback. The outer function can take parameters and pass them to the inner function. Thanks to Closures, the inner function can access the parameters in the parent scope. The outer function should now returns the inner one. That is actually a well-known trick.

Assume you use the Select2 plugin and want to have two callbacks. One is defined via the option templateResult and used for formatting select items in dropdown. Another is defined via the option templateSelection and used for formatting the displayed value in select field.
$(this).select2({
    ...
    templateResult: formatResultTemplate,
    templateSelection: formatSelectionTemplate
});

function formatResultTemplate(data) {
    ...
}

function formatSelectionTemplate(data) {
    ...
}
Assume, in both cases, the HTML code and formatting are similar except small differences in CSS styles. The functions have much repeated code and we would like to follow the don't-repeat-yourself principle (DRY). What is about to pass CSS style as parameter? And here you go (real example from project).
$(this).select2({
    ...
    templateResult: formatTemplate('margin:0 6px 0 0;'),
    templateSelection: formatTemplate('height:28px;')
});

function formatTemplate(style) {
    function formatWithStyle(data) {
        var imgSrc = $(data.element).data('image');
        if (imgSrc) {
            return "<img src='" + imgSrc + "' style='" + style + "'/>;<span class='option-text'>" + data.text + "</span>;";
        } else {
            return "<span class='option-text'>" + data.text + "</span>";
        }
    }

    return formatWithStyle;
}
The code is optimized now. The outer function formatTemplate returns the inner one formatWithStyle, "parametrized" with style. This inner function can be reused as "formatting callback".

I hope you got the idea.