Reputation: 791
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
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
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
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
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