Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bug in jQuery's element creation?

$(document).ready(function(){ var _new_li = $('', { 'id': 'p', 'text': 'CLICKME', click: function(){ alert('fired'); },
data: { 'somedata': 'somedata', }
});

_new_li.appendTo($("#example"));
});

I receive an "Uncaught TypeError: Cannot read property 'click' of undefined", when I try to click the element which I created like so. But, if you switch click: and data: it works.

$(document).ready(function(){
    var _new_li     = $('<li/>',     {
      'id':     'p',
      'text':   'CLICKME',
      data:     {
          'somedata':  'somedata',
      },
      click:    function(){
          alert('fired');
      }                      
    });

_new_li.appendTo($("#example"));
});

any explanation for that behavior?

Kind Regards

--Andy

PS:

I posted a similar behavior earlier in the jQuery Core Development forum, Mr. Swedberg answered there:

I'm pretty sure this is happening because you're setting data with an object, which >(until 1.4.2) would overwrite the event object. Not sure which version of jQuery you're >using in your project, but it looked like the jsbin example was using 1.4. Try upgrading >to 1.4.2 and see if that helps.

But it seems like the problem still exists in 1.4.2

like image 323
jAndy Avatar asked Apr 26 '10 12:04

jAndy


3 Answers

Post rewrited.

You shouldn't put that comma after last (and only) element in data.

After trying some stuff I got to this:

$(document).ready(function(){
    var fun=function(){
          alert('fired');
      };
    var parms={
      'id':     'p',
      'text':   'CLICKME',     
      'click':fun,         
      'data':     {
          'somedata':  'somedata'
      }
      };
      console.log(parms);
    var _new_li = $('<li/>',parms);

_new_li.appendTo($("#example"));
});

Everything works fine until I click on the li element. Then I get e is undefined (jquery line 55). Works well when click and data are swapped.

Still investigating

AND FOUND IT

jquery development version, line 1919

var events = jQuery.data(this, "events"), handlers = events[ event.type ];

events is undefined.

jquery overwrites events stored in data.

so this IS a bug. It should just extend.

I've submited a bug report.

like image 123
naugtur Avatar answered Nov 12 '22 14:11

naugtur


folks.. this is no bug.. what's happening is that you need to use the event data argument

.click( [ eventData ], handler(eventObject) )

eventDataA map of data that will be passed to the event handler.

to know why that's necessary you can review the discussion in the jquery documentation of .bind().. you may also want to review the concept of "closure" in javascript.. it provides the rationale behind this whole thing

this part is especially relevant (taken from http://api.jquery.com/bind/):

Passing Event Data

The optional eventData parameter is not commonly used. When provided, this argument allows us to pass additional information to the handler. One handy use of this parameter is to work around issues caused by closures. For example, suppose we have two event handlers that both refer to the same external variable:

var message = 'Spoon!';
$('#foo').bind('click', function() {
  alert(message);
});
message = 'Not in the face!';
$('#bar').bind('click', function() {
  alert(message);
});

Because the handlers are closures that both have message in their environment, both will display the message Not in the face! when triggered. The variable's value has changed. To sidestep this, we can pass the message in using eventData:

var message = 'Spoon!';
$('#foo').bind('click', {msg: message}, function(event) {
  alert(event.data.msg);
});
message = 'Not in the face!';
$('#bar').bind('click', {msg: message}, function(event) {
  alert(event.data.msg);
});

This time the variable is not referred to directly within the handlers; instead, the variable is passed in by value through eventData, which fixes the value at the time the event is bound. The first handler will now display Spoon! while the second will alert Not in the face!

like image 21
abbood1515 Avatar answered Nov 12 '22 13:11

abbood1515


I ended up modifying the source code slightly, so it would not randomly blow up here.

handle: function( event ) {
...

// tbn modified source
try {
   var events = jQuery.data(this, "events"), handlers = events[ event.type ];
} catch(e) {}
// tbn modified source

..then re-minified the source

I have not had any problems with this since (yet).

like image 1
tim Avatar answered Nov 12 '22 15:11

tim