How should I write a method that might be run only once or any number of times, but I want some logic to be run only once when the method is called?
Strange question, I know. Allow me to explain.
I have a JavaScript/jQuery function that is used to handle checkbox changes. here's some pseudo-code (FYI, I'm not actually trying to get the number of red rows - this is just PSEUDO CODE):
$("input[type='checkbox'].option").change(function() {
if ($(this).is(":checked")) {
$("div.special").removeClass("red");
}
else {
$("div.special").addClass("red");
}
// I only want to call this after all the checkbox event have been handled
updateNumRedDivs();
});
function updateNumRedDivs() {
alert($("div.special.red").length+"red DIVs found");
}
Now, the checkbox handler can be called either when an individual checkbox is clicked (obviously), or when a separate 开发者_高级运维"Select All" checkbox is called:
$(".myForm .selectAllCheckbox").change(function() {
var $checkboxes = $(this).closest("form").find("input[type='checkbox'].option");
if ($(this).attr("checked")) {
$checkboxes.each(function() {
if (!$(this).attr("checked"))
$(this).attr("checked", "checked").change();
});
}
updateNumRedDivs();
});
I hope this makes sense.
Separate the logic for the individual checkbox change handler into two functions. Then, for select all, just call the function you want, rather than invoking change()
:
function changeHandler(chkBox) {
if (chkBox.is(":checked")) {
$("div.special").removeClass("red");
}
else {
$("div.special").addClass("red");
}
}
$("input[type='checkbox'].option").change(function() {
changeHandler($(this));
updateNumRedDivs();
});
function updateNumRedDivs() {
alert($("div.special.red").length+"red DIVs found");
}
$(".myForm .selectAllCheckbox").change(function() {
var $checkboxes = $(this).closest("form").find("input[type='checkbox'].option");
if ($(this).attr("checked")) {
$checkboxes.each(function() {
if (!$(this).attr("checked"))
changeHandler($(this).attr("checked", "checked"));
});
}
updateNumRedDivs();
});
If you just want it to run once, just destroy the reference at the bottom of the function.
var updateNumRedDivs = function() {
// ... actual handling here
updateNumRedDivs = function(){};
}
Multiple times, I'd use a closure, like so
// This will run five times, before destroying
var updateNumRedDivs = function(amount) {
var calls = 0;
return function () {
// handle event
if (++calls === amount) updateNumRedDivs = function() {};
};
}(5)
Edit:
May have misunderstood your intent with a function that runs once or any number of times. Are you looking for a function that only runs once from every source, or a function that will not be limited by total calls, but instead by n calls from a single source?
here's the solution I came up with - not pretty, but it gets the job done:
$(".myForm input[type='checkbox']").change(function() {
if ($(this).hasClass("selectAllCheckbox") {
var $checkboxes = $(this).closest("form").find("input[type='checkbox'].option");
if ($(this).attr("checked")) {
$checkboxes.each(function() {
if (!$(this).attr("checked"))
$(this).attr("checked", "checked").change();
});
}
}
else {
if ($(this).is(":checked")) {
$("div.special").removeClass("red");
}
else {
$("div.special").addClass("red");
}
}
updateNumRedDivs();
});
function updateNumRedDivs() {
alert($("div.special.red").length+"red DIVs found");
}
Basically, I consolidated into one change handler, and made it recursive.
I would do it by passing extra params to the change event through trigger
:
NOTE: dumbed down to illustrate the idea.
http://jsfiddle.net/bnWVd/
function doit(){
alert("done");
}
$("input").click(function(event,extraParams){
// do stuff
if(extraParams && extraParams.noAlert){
// do nothing or maybe something else
}else{
doit();
}
});
$("button").click(function(){
$("input").each(function(){
$(this).trigger("click",{noAlert: true});
});
doit();
});
Basically, when called in the loop I pass a parameter to the event letting it know not to run the extra function. Then when the loop is done I call it directly. If no parameter is passed it will be called.
Too Much Of Code Alright you don't want the Change event of the Single Check Box fired when you select the Select ALL CheckBox
var SelectALLFired=false;
In the handler of the SelectALLCheckBox Make the value for SelectALLFired=true; and upon completion change the value back to SelectALLFired=false;
on the Single CheckBox Change function before doing anything write an If Statement
if(!SelectALLFired)
{
Your Code
}
$(".myForm .selectAllCheckbox").change(function() {
SelectALLFired=true;
var $checkboxes = $(this).closest("form").find("input[type='checkbox'].option");
if ($(this).attr("checked")) {
$checkboxes.each(function() {
if (!$(this).attr("checked"))
$(this).attr("checked", "checked").change();
});
}
SelectALLFired = false;
updateNumRedDivs();
})
$("input[type='checkbox'].option").change(function() {
if(!SelectALLFired)
{
if ($(this).is(":checked")) {
$("div.special").removeClass("red");
}
else {
$("div.special").addClass("red");
}
}
// I only want to call this after all the checkbox event have been handled
updateNumRedDivs();
});
精彩评论