2

I have tried to search for an answer to this, but my wording is too similar to the questions that are looking for event delegation using the jQuery on() method. Consequently, please do not get confused by the wording of my question.

I feel ashamed that I am actually asking this question given my experience with writing jQuery applications, but I must confess that I do not actually know the answer to this :-(

Consider this:

// Create the div
$('#wrapper').prepend('<div id="test"></div>');

// Add content to the div, and attach events
// Only execute it once the div has been created though, so wait 20 milliseconds
setTimeout(function(){

    // Add some button
    $('#test').html('<button></button>');

    // Add an event to the button
    // ... after 20 milliseconds
    setTimeout(function(){

        // Attach the click event
        $('#test button').click('dosomething');
    });
},20);

In the above code, I have had to use setTimeout to ensure that the element has been created before selecting it and adding content, events etc...

My question, quite simply, is there a better way to do this? Without timeouts?

Please note I do not mean, is there a better way to write the exact code above? I simply want to know if there is a way to avoid using timeouts for the reason specified.

Ben Carey
  • 16,540
  • 19
  • 87
  • 169
  • 1
    *"I have had to use `setTimeout` to ensure that the element has been created before selecting it and adding content, events etc..."* No you don't. http://jsfiddle.net/LVH7w/ – the system Mar 01 '13 at 20:02
  • Perhaps I don't get what is the need of the inmediately created, why can't you use on? – pdjota Mar 01 '13 at 20:04
  • @thesystem Funnily enough that is how I originally wrote my code, but it didnt work! It only worked once I inserted the timeouts. That is why I am so confused!!! :-( – Ben Carey Mar 01 '13 at 20:04
  • Appending new children or HTML is synchronous operation, so you don't need any timeout. – dfsq Mar 01 '13 at 20:04
  • @dfsq I know, that is why I am so confused. I only added the timeouts because it didnt work without them – Ben Carey Mar 01 '13 at 20:05
  • 1
    @thesystem Okay, will do my best. My application is very large, this is just a small snippet. Might take me some time to create a working jsFiddle. Thanks for your help so far. I am glad that you agree the timeouts are not necessary... – Ben Carey Mar 01 '13 at 20:08
  • @thesystem I am struggling to recreate the issue now. Not helped by the fact that I wrote this code a few months ago. I saw it today and noticed these nested timeouts. I then remembered why I put them there, and resultantly wanted to see if it was normal. I can't understand why it wasn't working before, and now it is. Sod's bloody law eh! I will post something here if I am able to recreate this. I am sure I will be, as this is not the first time I have encountered this issue... Thanks anyway, and sorry to waste your time – Ben Carey Mar 01 '13 at 20:19
  • @BenCarey: No problem. Let me know if you figure it out. I know sometimes people use timeouts if it takes a long time for the browser to redraw the window, but that should usually only happen when you're appending a very large DOM. – the system Mar 01 '13 at 20:24
  • @thesystem This is a very large DOM. Are you saying that timeouts might be necessary on a very large page, especially if the clients computer is not very good? or is this irrelavent? – Ben Carey Mar 01 '13 at 20:26
  • @BenCarey: When appending a lot of new elements at the same time, it can freeze the browser a bit. Some people might break up the append using `setTimeout`. – the system Mar 01 '13 at 21:00

5 Answers5

2

This could help.

 var _b = $('<button></button>');
    $('#wrapper').prepend(_b);
    _b.click(function(){
     ///do something
    });
Senad Meškin
  • 13,597
  • 4
  • 37
  • 55
  • 1
    no need for the ``, jQuery will create the element for you with just `$(' – Jeremy T Mar 01 '13 at 20:09
  • Thanks for you help, I will come back when I am able to recreate the exact issue in a jsFiddle. It now seems to be working, cannot understand why as it definitely wasnt before... – Ben Carey Mar 01 '13 at 20:22
0

Assuming that the wrapper exists on the DOM when you are adding the code try:

$('#wrapper').on('click', '#test button', doSomething)
pdjota
  • 3,163
  • 2
  • 23
  • 33
  • Please read the question, I am not looking for event delegation. I am well aware of how to achieve this! – Ben Carey Mar 01 '13 at 20:03
  • So if you don't need event delegation what do you need? To listen to the change in the DOM? What are you thoughs about this: http://stackoverflow.com/questions/9488653/jquery-how-to-listen-for-dom-changes – pdjota Mar 01 '13 at 20:08
0

This works for me jsFiddle

var $test = $('<div id="test"></div>');
  , $button = $('<button></button>')
$test.append($button);

$button.click(function() {
  console.log('here');
});

$('#wrapper').prepend($test);
bmavity
  • 2,477
  • 2
  • 24
  • 23
  • Thanks for you help, I will come back when I am able to recreate the exact issue in a jsFiddle. It now seems to be working, cannot understand why as it definitely wasnt before... – Ben Carey Mar 01 '13 at 20:23
0

This is how I will do it in one line: http://fiddle.jshell.net/4rT6s/1/

$(function(){
    $('<button type="button">Click!</button>').click(function(){alert('click');}).appendTo($('<div id="test" />').appendTo('#wrapper'));
});
Alqin
  • 1,305
  • 3
  • 16
  • 35
  • Thanks for you help, I will come back when I am able to recreate the exact issue in a jsFiddle. It now seems to be working, cannot understand why as it definitely wasnt before... – Ben Carey Mar 01 '13 at 20:27
0

I think that you can chain the methods with a little hack to get the children just created:

$('#wrapper').prepend('<div id="test"></div>').children('#test').html('<button></button>').children('button').click('dosomething');

it's ugly but it seems to work, i'm not sure if it's scalable to your needs

arieljuod
  • 15,460
  • 2
  • 25
  • 36
  • Thanks for you help, I will come back when I am able to recreate the exact issue in a jsFiddle. It now seems to be working, cannot understand why as it definitely wasnt before... – Ben Carey Mar 01 '13 at 20:23