jQuery bind custom function to appended element

I am trying to create a web app that will allow a user to define a custom JavaScript function and then add a button to their user interface that well preform that function.

Here is a sample of the code

var customCommands = {
  command1: {
    text: 'Hello Console',
    cFunctionRun: function() {
      console.log('hello Console!');
    }
  },
  command2: {
    text: 'Hello World',
    cFunctionRun: function() {
      alert('hello World!');
    }
  }
}

Then I wrote a small function that loops though and builds the buttons and adds them to the user interface. The problem is when I append the elements to the user interface than click on the buttons nothing works...

Here is one of the methods I tried

for (var cmd in customCommands) {
    command = customCommands[cmd];
    button = $('<button/>').html(command.text).on('click', 
      function(){ 
        console.log(command.text); 
        command.cFunctionRun(); 
      }
    );
}
buttonContainer.append(button);

Now my loop builds everything just fine and even the .on('click') works, but it always displays the text of the lasted added command?

here is http://jsfiddle.net/nbnEg/ to show what happens.

Answers:

Answer

When you actually click, the command variable points to last command (as the whole loop has already run). You should maintain data state per button which tells it which command to invoke. You should do this.

for(var i in customCommands) {
  if(customCommands.hasOwnProperty(i)){ //this is a pretty important check
    var command = customCommands[i];
    button = $('<button/>').html(command.text).data("command_name", command).on('click', function(){ 
      console.log($(this).data("command_name").text); 
      $(this).data("command_name").cFunctionRun(); 
    });

    $("body").append(button);
  }
}

JSFiddle

Answer

all you need is passing the parameter with function, you should try this

Answer

It's a (missing) closure problem. The event handler will keep a reference to the value of command on the last iteration of the loop. To solve it you can create a new scope, using an immediately invoked function:

for(var cmd in customCommands) {
    (function(command){
        button = $('<button/>').html(command.text).on('click', 
          function(){ 
            console.log(command.text); 
            command.cFunctionRun(); 
          }
        );
        buttonContainer.append(button);
    }(customCommands[cmd]));
}
Answer

Since the buttons should be unique (no reason for creating duplicates), I'm setting the button id to the name of the customCommands (command1 and command2 in this example). This example could easily be adapted to use any of the relative attributes (data-*, name, etc...).

Create a click event listener on document for whenever one of your buttons are pressed. Then call the function associated with the given id.

$(document).on("click", "button", function(){
    customCommands[this.id].cFunctionRun();
});

for(var command in customCommands){
    var button = $('<button id="' + command +'"/>').html(customCommands[command].text);
    $("body").append(button);
}

EXAMPLE

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.