1

The question title may not be really clear or even inaccurate. However, this is what I want to do.

I want to have an array of objects. Each object will be a button. I want to bind predefined function to each button. A sample of the code is here.

Currently, I'm using eval() but I know it's slow and and is considered a bad practice due to security reason. And it doesn't work either because the eval() function will execute right away and call the 2 functions that have been declared.

Can someone please suggest me what's the best approach to achieve my goal?

Thanks

3 Answers 3

3

Fixed it for you here: http://jsfiddle.net/tAZvz/2/

Basically what FishBasketGordo said about storing the functions, but also you have to use jQuery's click function to bind the events, not assign to onclick, since they are wrapped elements.


var func1 = function() { alert("Function 1 is called");}
var func2 = function() { alert("Function 2 is called");}

var myArray = [{id:"bt1", value:"+", func: func1},
               {id:"bt2", value:"-", func: func2}];


$(function(){
    for(var i=0;i<myArray.length;i++){
       var button = $('<input type="button">');
       button.attr('id',myArray[i].id).attr('value',myArray[i].value);

       button.click(myArray[i].func);

       $('#test').append(button);
    }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot for your effort, Magnar. I accepted FishBasket because he answered earlier. But +1 for your jsFiddle. Thanks.
You're absolutely right about click versus assigning to onclick. I was correcting my answer as you posted.
1

Just store the function in the array.

var myArray = [{id:"bt1", value:"+", func: func1 },
               {id:"bt2", value:"-", func: func2 }];

Then set the click event handler:

button.click(myArray[i].func);

5 Comments

that will make the array extremely huge and hard to read. What if the function spread several line long?
You can declare the function elsewhere and just put the name of the function in the array, as I have above.
Thanks a lot FishBasket. It works. BTW, do you know what's the difference btw writing obj.click(function(){}) and obj.bind('click', function(){})? Thanks
The first is shorthand for the second. Functionally, they are the same. I recommend reading through the jQuery API documentation: api.jquery.com. It's very informative.
@chepukha: .bind() does let you set data on the event object which is accessible via event.data.someProperty.
1

You can shorten your code quite a bit like this:

var func1 = function() { alert("Function 1 is called");}
var func2 = function() { alert("Function 2 is called");}

    // changed property name ----------v
var myArray = [{id:"bt1", value:"+", click: func1},
               {id:"bt2", value:"-", click: func2}];

$(function(){
    $.each( myArray, function(i,v) {
       $('<input>',$.extend({},v,{type:"button"})).appendTo('#test');
    });
});

Example: http://jsfiddle.net/yLPsK/

I used the jQuery.each()[docs] method to iterate your Array.

Then I used the jQuery.extend()[docs] method to extend an empty object with the objects you created (changing func to click), as well as another one with the type:"button" info, and passed the result as the second argument to the jQuery()[docs] method.

If you add type:"button" to each object in your array, you can get rid of $.extend.

var func1 = function() { alert("Function 1 is called");}
var func2 = function() { alert("Function 2 is called");}

    // changed property name ----------v
var myArray = [{id:"bt1", value:"+", click: func1, type:"button"},
               {id:"bt2", value:"-", click: func2, type:"button"}];
    // added the "type" property -------------------^

$(function(){
    $.each( myArray, function(i,v) {
       $('<input>', v).appendTo('#test');
    });
});

Example: http://jsfiddle.net/yLPsK/1/

6 Comments

+1 . Thanks a lot Patrick. Your answer is very helpful.However, I didn't use each() because I need to control the number of buttons per row (that code was not included in my question), e.g. 3 buttons per row. And so each() does not allow me to do that, I guess?!
@chepukha: If you're saying that you need to break the loop after 3 buttons have been added, then just add if( i == 2 ) return false; to the $.each method. When i == 2, it will return false, and break the loop.
I couldn't post this extension as an answer to be clearer for reading because I don't have enough reputation. Sorry. I actually wanted to do something more beside calling the predefined functions when users click on the button. Detail here Because of closure, if I use myArray[i].func inside the anonymous function, 'i' will be equal to '2' and myArray[i].func becomes undefined. How would I fix this problem?
@chepukha: You need to create a new variable scope that captures the current value of i. Because a new variable scope is created in a function, you'd need to call a function, pass i to it, and have it return a function as the handler. Because the returned function was created in the same scope (the function) where i was passed, it will continue to have access to that i value. Using $.each is a nice way because you have a function execution for each iteration that references an i value. Any function created inside that $.each will continue to have access to i.
...here's another example using $.each() jsfiddle.net/yLPsK/3 The click handlers created in the $.each() function reference myArray[i].func. Because i is a parameter to that specific function invocation, the handler created will continue to reference that specific i.
|

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.