J Hunt
J Hunt

Reputation: 791

Avoid repeating jQuery code

If I have code like what is shown below, is there any way of avoiding the need of repeating the code over and over again?

 $("#ClearSign1").click(function () {
    signaturePad1.clear();
 });
 $("#ClearSign2").click(function () {
    signaturePad2.clear();
 });
 $("#ClearSign3").click(function () {
    signaturePad3.clear();
 });
 $("#ClearSign4").click(function () {
    signaturePad4.clear();
 });
 $("#ClearSign5").click(function () {
    signaturePad5.clear();
 });

I can do this:

 for(var i = 1; i < 6; i++) {
    $("#ClearSign" + i).click(function () {
       signaturePad1.clear();
    });
 }

But how do I handle the signaturePad1 variable? I need it to have the 1 updated to 2, 3, 4, 5 as looping through.

Upvotes: 1

Views: 135

Answers (4)

Pranav C Balan
Pranav C Balan

Reputation: 115222

Use attribute starts with selector which helps to avoid the for loop. Then store the variable reference in an array to get reference based on the index on click event.

// store the variable refernce in an array
var sign = [signaturePad1, signaturePad2, signaturePad3, signaturePad4, signaturePad5];
// assign click envent to elements and also cache the elements to get index
var $ele = $('[id^="ClearSign"]').click(function() {
  // get element by index and apply clear
  sign[$ele.index(this)].clear();
});

Or in case the variables are in global context then you can get it from window object.

var $ele = $('[id^="ClearSign"]').click(function() {
  // get element by index from window object and apply clear
  window['signaturePad1' + ($ele.index(this) + 1)].clear();
}); 

Upvotes: 2

nem035
nem035

Reputation: 35491

But how do I handle the signaturePad1 variable? I need it to have the 1 updated to 2, 3, 4, 5 as looping through.

Well, the most obvious way to clean this up without altering much of your code is to invoke the signaturePad# method on the object on which its scoped to, using the bracket notation. In the outer most scope, that is the window object:

ES5 solution: You must wrap the invocation in an IIFE, which will maintain the value of i properly for each callback within the closure of that IIFE.

for(var i = 1; i < 6; i++) {
  $("#ClearSign" + i).click(function () {
   (function(idx) {
     // in here idx is always the proper i value
     window['signaturePad' + idx].clear();
   })(i); 
  });
}

Or you can create an array of your clearSign functions and use a forEach, which would maintain the proper scope. Or create an array of click callbacks, as Pranav C Balan showed.

ES6 solution: (use let instead of var):

for(let i = 1; i < 6; i++) {
  $("#ClearSign" + i).click(function () {
     window['signaturePad' + i].clear();
  });
}

Using let makes i block scoped within the loop block. This properly captures the value for the callbacks and keeps us from polluting the global scope. Not to mention, it keeps the code more readable and concise - nested IIFE's inside for loops don't really add to code clarity and can cause confusions.

Upvotes: 4

John williams
John williams

Reputation: 731

Didn't see you were calling multiple methods in the click events

$('[id^="ClearSign"]').click(function () {
   var id = $(this).attr("id").split("ClearSign", "")[1];
   signaturePad + id.clear();
});

Upvotes: 0

Mohit Bhardwaj
Mohit Bhardwaj

Reputation: 10083

You can give all divs a common class e.g. 'clickables' . Then bind click event using that class as a selector.

$(".clickables").on("click", function(e){
  var targetObject = $(this).attr("id").replace("ClearSign", "signaturePad");
  window[''+targetObject].clear();
});//click

Upvotes: 0

Related Questions