0

I'm creating a template for handling form buttons.

The idea is on first run of a function (when i lock a form), said function will create onClick listeners for buttons to edit, cancel, delete, etc that will trigger their respective functions (hardcoded in global scope)

The part of the code that's giving me headaches is:

//Build standard button actions on first call...
if(window[form_elem_tag + "funcs"] == 1) return;
window[form_elem_tag + "funcs"] = 1;


var b2n_act = 'edit';
var func_name = form_elem_tag + "_" + b2n_act;
var b2n_name = form_elem + "_btn_" + b2n_act;
$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();

});
console.log("funcName created: " + func_name);

var b2n_act = 'cancel';
var func_name = form_elem_tag + "_" + b2n_act;
var b2n_name = form_elem + "_btn_" + b2n_act;
$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();

});
console.log("funcName created: " + func_name);

In the above scenario, i created the actions for the EDIT button , and the the CANCEL button.

The problem im having is that the when i click the EDIT button the listener that fires is of the CANCEL button..

console logged: enter image description here

and when i reverse the order, it becomes apparent that what ever is the last listener I create , its function seems to fire for all buttons..

What's wrong with my code?

3
  • What is form_elem_tag ? A string? what are (some of) the possible values? Commented Mar 1, 2015 at 2:29
  • Can you create a jsFiddle? Commented Mar 1, 2015 at 3:05
  • Aduch - form_elem_tag is basically a copy of the form name/id w/o the hash eg. #myForm vs myForm Commented Mar 1, 2015 at 3:11

2 Answers 2

1

This is an issue with closures (link MDN).

Think about it this way: We've defined 3 variables

var b2n_act, func_name, b2n_name

that our event handlers reference. So, when we do this:

var b2n_act = 'edit';
var func_name = form_elem_tag + "_" + b2n_act;
var b2n_name = form_elem + "_btn_" + b2n_act;

$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();
});

At this point, yes - func_name is form_elem + "_btn_" + b2n_act. Clicking the button will look up the variable func_name, and do what we want properly. However, we then do this:

var b2n_act = 'cancel';
var func_name = form_elem_tag + "_" + b2n_act;
var b2n_name = form_elem + "_btn_" + b2n_act;

$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();
});

And this is where the problem begins. Our variables have been updated, and the second event listener works properly, but the fist event handler still references the variables. (If you're thinking "BUT wait! I've defined my variable again with var, checkout this section on "hoisting" - basically, they're all moved up top)

So, how can you fix this? Easy! We just have to remember that JavaScript allows for function level scope. How about we pass in a value which we'll scope to our function, like this:

(function(func) {
    $(b2n_name).on("click",function(){
        console.log("calling " + func);
        window[func]();
    });    
}(func_name));

JSFiddle: http://jsfiddle.net/Lhye0p37/

For those reading, if you're not familiar with this (function(){...}()) thing, it's an immediately invoked function expression (or IIFE). We pass in the func_name, and reference it by func within our event handler. Now, each event handler will work as expected.

Another way is passing the information necessary to bind your event handlers to a function. Something like this:

function bindHandler($el, func) {
    $el.on("click", function(){
        console.log("calling " + func);
        window[func]();
    });  
}

JSFiddle: http://jsfiddle.net/Lhye0p37/1/

Sign up to request clarification or add additional context in comments.

Comments

0

The issue here is that you are redefining the event on the button twice on:

$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();

});

and then again :

$(b2n_name).on("click",function(){
    console.log("calling " + func_name);
    window[func_name]();

});

Not sure what your intent here is but normally you define an event handler for a button once, because rewriting the same event handler later it will simply replace the first one.

1 Comment

actually I'm not .. im defining a handler for each button .. the b2n_name is a variable ( var b2n_name = form_elem + "btn" + b2n_act; ) it represents the following #myForm_btn_edit , #myForm_btn_cancel, and so on

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.