ilyo
ilyo

Reputation: 36421

Can I define variables as arguments?

I have the following use of jQuery UI function:

$('.droppable').droppable({
    tolerance: 'touch',
    over: function () {
        var hasHiddenList = $(this).children('ul.hidden');
        if (hasHiddenList.length)
            hasHiddenList.removeClass('hidden');
    },
    out: function () {
        var hasEmptyList = $(this).children('ul.empty');
        if (hasEmptyList.length)
            hasEmptyList.addClass('hidden');
    },
    drop: function () {
        var hasEmptyList = $(this).children('ul.empty');
        if (hasEmptyList.length)
            hasEmptyList.removeClass('empty');
    }
});

And I am wondering if I can define the variables hasHiddenList and hasEmptyList outside the callback functions, since it is the same variable in all of them.

Upvotes: 0

Views: 78

Answers (2)

Jakob
Jakob

Reputation: 24370

If you really, really want the variables, there are two options.

The obvious one (with pitfalls) is this:

var hasHiddenList = $('.droppable').children('ul.hidden');
var hasEmptyList = $('.droppable').children('ul.empty');

$('.droppable').droppable({
    tolerance: 'touch',
    over: function () {
        if (hasHiddenList.length)
            hasHiddenList.removeClass('hidden');
    },
    out: function () {
        if (hasEmptyList.length)
            hasEmptyList.addClass('hidden');
    },
    drop: function () {
        if (hasEmptyList.length)
            hasEmptyList.removeClass('empty');
    }
});

Variables have been extracted, the code is less repetitive. All good.

Now, the problem is that the selectors are just run once. The callback over, out and drop are called every time one of those events occur, but hasHiddenList and hasEmptyList will not have been updated; they will still be the same thing between every invocation. Probably not what you want.

The way to remedy this is to use functions instead of variables, like this:

var hiddenList = function(target) {
    return $(target).children('ul.hidden');
};
var emptyList = function(target) {
    return $(target).children('ul.empty');
};

$('.droppable').droppable({
    tolerance: 'touch',
    over: function () {
        var list = hiddenList(this);
        if (list.length)
            list.removeClass('hidden');
    },
    out: function () {
        var list = emptyList(this);
        if (list.length)
            list.addClass('hidden');
    },
    drop: function () {
        var list = emptyList(this);
        if (list.length)
            list.removeClass('empty');
    }
});

This abstracts away how the queries are performed (you only have to write $(target).children('ul.empty'); once instead of twice) but in reality the code has not really become simpler. Actually, I would even say that it's harder to follow it now. On the other hand, if you were using the same selector even more than twice, lets say five times, then maybe this would actually be useful.

Also, note that I've removed "has" from the variable names, because "has" makes it sound like they are booleans, which they are not. They are lists of elements.

Upvotes: 1

Jakob
Jakob

Reputation: 24370

Better yet, you don't even need the if-statements and the variables:

$('.droppable').droppable({
    tolerance: 'touch',
    over: function () {
      $(this).children('ul.hidden').removeClass('hidden');
    },
    out: function () {
      $(this).children('ul.empty').addClass('hidden');
    },
    drop: function () {
      $(this).children('ul.empty').removeClass('empty');
    }
});

Upvotes: 5

Related Questions