Robert Deniro Robert Deniro - 3 months ago 11
Javascript Question

Shorten These jQuery functions

I have these 3 jQuery functions that basically do the same thing, but they are a tiny bit different (width of window, and class that is removed/toggled)

I need the functionality of all these 3 functions, but want to somehow combine them/shorten them into one function. I've tried to but my code keeps breaking
Can anyone help to shorten them?

Here are the 3 functions

jQuery(document).ready(function($) {
$('.exampleimg').click(function() {
$('.about').hide(600);
if (($(window).width() > 670) && ($(this).hasClass('exampleimgopen'))) {
$(this).removeClass('exampleimgopen');
} else if ($(window).width() > 670) {
$('.exampleimg').removeClass('exampleimgopen');
$(this).addClass('exampleimgopen');
}
});
});

jQuery(document).ready(function($) {
$('.exampleimg').click(function() {
$('.about').hide(600);
if (($(window).width() < 670) && ($(this).hasClass('exampleimgopen2'))) {
$(this).removeClass('exampleimgopen2');
} else if ($(window).width() < 670) {
$('.exampleimg').removeClass('exampleimgopen2');
$(this).addClass('exampleimgopen2');
}
});
});

jQuery(document).ready(function($) {
$('.exampleimg').click(function() {
$('.about').hide(600);
if (($(window).width() < 540) && ($(this).hasClass('exampleimgopen3'))) {
$(this).removeClass('exampleimgopen3');
} else if ($(window).width() < 540) {
$('.exampleimg').removeClass('exampleimgopen3');
$(this).addClass('exampleimgopen3');
}
});
});

Answer

I need the functionality of all these 3 functions, but want to somehow combine them/shorten them into one function.

Generally, a good approach when refactoring similar functions is to create a single factory function that will take your variable data as arguments and return a function that has access to that data via its closure.

function myFactory(conditionFunc, windowWidth, cssClass) {
  return function() {
    $('.about').hide(600);
    var windowCondition = conditionFunc($(window).width(), windowWidth);
    if (windowCondition && ($(this).hasClass(cssClass))) {
      $(this).removeClass(cssClass);
    } else if (windowCondition) {
      $('.exampleimg').removeClass(cssClass);
      $(this).addClass(cssClass);
    }
  }
}

Then you can call this function 3 times to build your functions:

// helper methods that will perform '<' or '>' on window width
var lessThan = function(a, b) { return a < b; };
var greaterThan = function(a, b) { return a > b; };

var func1 = myFactory(greaterThan, 670, 'exampleimgopen');
var func2 = myFactory(lessThan, 670, 'exampleimgopen2');
var func3 = myFactory(lessThan, 540, 'exampleimgopen3');

Which you can then pass each into their corresponding listeners.

$('.exampleimg').click(func1);
$('.exampleimg').click(func2);
$('.exampleimg').click(func3);

The advantage of doing things this way is that you only write a single function which then creates different versions of your listener callback functions, based on the data you give to it.