Mikhail Kashtaev Mikhail Kashtaev - 10 days ago 6
Javascript Question

JQuery click event attaches to more than one element

I have a function that creates button elements in dialog header. However, the click event gets attached to all the buttons instead of current button.

_createTitlebarButtons : function(){
for (var each in this.options.titlebarButtons ) {
var self = this,
props = this.options.titlebarButtons[each];


if ( !props.icon ){ props.icon = ""}
if ( !props.name ){ props.name = "button-"+each.toString()}
if ( !props.click ){ props.click = function(){} }
if ( !props.text ){ props.text = "" }

var curButton = $( "<button type='button' id='btn-"+each+"' ></button>" ).button({
type: "button",
label: $( "<a>" ).text( props.text ).html(),
icon: props.icon,
showLabel: false
})
.attr("name", props.name)
.css("right", 3+22*(Number(each)+1))
.appendTo( this.uiDialogTitlebar )
.on( "click", function( event ) {
event.preventDefault();
props.click.apply( self.element[ 0 ], arguments );
});

this._addClass( curButton, "ui-dialog-titlebar-close" );
}
},


All the icons and classes work. However, the click event gets attached to all the buttons instead of one button. So if I have multiple buttons the click event is going to be the same for all buttons. And its going to be the click event of the last button. So:

titlebarButtons : [
{
name: "button1",
text: "tooltip",
icon: "ui-icon-heart",
click:function(){
console.log("Button1 Clicked");
console.log(this);
}
},
{
name: "button2",
text: "tooltip",
icon: "ui-icon-close",
click:function(){
console.log("Button2 Clicked");
console.log(this);
}
}
]


Will create 2 buttons but on click they both will be saying "Button2 Clicked" whereas the first one should say "Button1 clicked".

EDIT: Had to use $.each instead of for loop because of scope problems.

$.each( this.options.titlebarButtons, function(index){
console.log(this);

var props = this;

if ( !props.icon ){ props.icon = ""}
if ( !props.name ){ props.name = "button-"+index}
if ( !props.click ){ props.click = function(){} }
if ( !props.text ){ props.text = "" }

var curButton = $( "<button type='button' ></button>" ).button({
type: "button",
label: $( "<a>" ).text( props.text ).html(),
icon: props.icon,
showLabel: false
})
.attr("name", props.name)
.css("right", 3+22*(Number(index)+1))
.appendTo( self.uiDialogTitlebar )
.on( "click", function( event ) {
event.preventDefault();
props.click.apply( self.element[ 0 ], arguments );
});


self._addClass( curButton, "ui-dialog-titlebar-close" );
} )

Answer

Created the following example: https://jsfiddle.net/Twisty/ookwg8bq/

jQuery

$(function() {
  var uiDialog = {
    options: {
      titlebarButtons: [{
        name: "button1",
        text: "tooltip",
        icon: "ui-icon-heart",
        click: function() {
          console.log("Button1 Clicked");
          console.log(this);
        }
      }, {
        name: "button2",
        text: "tooltip",
        icon: "ui-icon-close",
        click: function() {
          console.log("Button2 Clicked");
          console.log(this);
        }
      }]
    },
    uiDialogTitlebar: "#uiDialogTitlebar",
    _createTitlebarButtons: function() {
      var self = this;
      $.each(self.options.titlebarButtons, function(ind, elem) {
        var props = self.options.titlebarButtons[ind];

        if (!props.icon) {
          props.icon = ""
        }
        if (!props.name) {
          props.name = "button-" + ind
        }
        if (!props.click) {
          props.click = function() {}
        }
        if (!props.text) {
          props.text = ""
        }

        var curButton = $("<button>", {
            type: 'button',
            id: 'btn-' + ind,
            name: props.name,
            class: "ui-dialog-titlebar-close"
          }).button({
            type: "button",
            label: props.text,
            icon: props.icon,
            showLabel: false
          })
          .css("right", 3 + 22 * (ind + 1))
          .appendTo(self.uiDialogTitlebar)
          .click(function(event) {
            event.preventDefault();
            props.click.apply(elem, []);
          });
      });
    }
  };

  uiDialog._createTitlebarButtons();

});

This creates both buttons and you can click on each button. They sort of overlap due to the right styling. I get the following results in FireFox w/FireBug console:

Button1 Clicked
/_display/ (line 73)
Object { name="button1",  text="tooltip",  icon="ui-icon-heart",  more...}
/_display/ (line 74)
Button2 Clicked
/_display/ (line 81)
Object { name="button2",  text="tooltip",  icon="ui-icon-close",  more...}