views:

36

answers:

2

Hi,

I have few div HTML elements and i am cloning it with a clone(true) option as i want to copy the events also.

Now the case there are certain click events in my HTML div blocks and while crating events i use context parameter also like

var $block ="<div class='task-create-content' >"+
                 "<div class='task-create-preview'>"+
                      "<div class='items'>" +
                           "<div><input type='text' class='edit wtp'/></div>" +
                           "<div><input type='text' class='edit wtp'/></div>" +
                      "</div>"+
                 "</div>");

$(".wtp", $block).live('click',function() {
     alert("hi");
})

Now , when i clone this block using clone(true), click event doesn't get fire even if i am assigning context parameter.

+1  A: 

The .live() method needs the actual selector to match the element against.

Try this:

$(".task-create-content .wtp").live('click',function(){
     alert("hi");
});

It uses that selector at the root of the document to see what exactly received the click event. If there's a match, it fires the handler for that selector.

It seems as though you're assigning handlers directly for newly created elements. If you want to do that, use .bind().

$(".wtp",$block).bind('click',function(){
     alert("hi");
});

...which is the same as doing:

$(".wtp",$block).click(function(){
     alert("hi");
});

EDIT:

The correct A couple of ways to confine a live() event to $block would be to pass $block as a third argument to live().

$(".wtp").live('click',function(){
     alert("hi");
}, $block); // The handler is placed on $block and fired for .wtp elements within

...which is the same as using .delegate()

  // The handler is placed on $block and fired for .wtp elements within
$block.delegate('.wtp', 'click', function(){
     alert("hi");
});

jQuery's .delegate() just nicer packaging for passing the third argument to .live(). It just reorders the arguments, and calls .live().

http://github.com/jquery/jquery/blob/master/src/event.js#L875

patrick dw
I think it's not so much that the live() needs the actual selector instead of a context. According to the docs: "As of jQuery 1.4, live events can be bound to a DOM element "context" rather than to the default document root." http://api.jquery.com/live/I would guess that the $block variable is not considered a DOM element context b/c it hasn't been appended anywhere in the document yet. You could add the element to the DOM, and then use a selector for it as part of your context, but then you're basically at patrick dw's solution anyway.
joelt
@joelt - Yes, `live()` events can be bound to a context (this is what makes `delegate()` work), but `live()` does rely on a proper selector. When you do `$(".wtp",$block).live(...`, jQuery flips it around to `$block.find(".wtp").live(...`, which means the event will be fired for all `.wtp` elements instead of just the ones contained in the `$block`. In order to apply a context to `.live()` as the docs suggest, you would need to pass `$block` as a third argument to `live()`. When there's no third argument present, `live()` uses the document root.
patrick dw
@patrick - you can ectually use `$block` as the context for `live`, but in that case $block must be a single DOM element, you can achieve this using `$block = $("...");` -- I try and explain it in my answer.
Peter Ajtai
+1  A: 

First, You have an extraneous closing parenthesis at the end of your $block declaration:

var $block = ...  "</div>");

This would stop the whole page from working.


Second, if you use a context as part of the live(), then the context has to be a single DOM elemnt.... it cannot be a string. To create a single DOM element, simply make use of jQuery ( $block = $("...");, so you should do:

var $block =$("<div class='task-create-content' >"+
                 "<div class='task-create-preview'>"+
                      "<div class='items'>" +
                           "<div><input type='text' class='edit wtp'/></div>" +
                           "<div><input type='text' class='edit wtp'/></div>" +
                      "</div>"+
                 "</div>");

Then when you refer to $block you will be referring to a DOM element. The context cannot simply be $block, since you want to bind the click function to a $block that is actually on the page in question, so you have to specify which $block/s. To do this use $(".wtp", $block[0]).

$(".wtp", $block[0]).live('click',function() {
     alert("hi");
})

I pick as the context the first $block in the DOM. You can substitute a variable for the index or do this some other way.

working jsFiddle example


Working with clones

Instead of using live(), I would use bind() to work with clones... like this:

Remember that $block must be a DOM element in this case too, so you have to define $block like:

$block = $(" ... ");

Then you can use and clone $block like this:

$(".wtp", $block).bind('click',function() {
     alert("hi");
})

$($block).clone(true).appendTo("body");

  // Let's change $block dynamically!
$("<div>Dynamic!</div>").appendTo($block);

$($block).clone(true).appendTo("body");

Make sure you include true when you clone so that you indicate that the event handlrs should be copied too.

jsFiddle example

Peter Ajtai
+1 - You're right. That surprises me a little. jQuery must track the original context which is then referenced by `.live()`.
patrick dw
Although, I do think that OP is ultimately trying to make `live()` work for his dynamically generated (cloned) elements. While a context could be applied by various means, it seems like he's ultimately trying to achieve `$(".task-create-content .wtp")`, since he's not adding `.wtp` elements to `.task-create-content` elements, but rather adding/cloning the entire `.task-create-content` with the `.wtp` inside.
patrick dw
@patrick - I think that's true. I also think using `bind()` in that case would be much simpler. I added this option, demonstrating that you can even change `$block` dynamically if you use `bind()`.
Peter Ajtai