newtonapple
newtonapple

Reputation: 4133

How to Maintain Correct Javascript Event After Using cloneNode(true)

I have a form element that contains multiple lines of inputs. Think of each line as attributes of a new object that I want to create in my web application. And, I want to be able to create multiple new objects in one HTTP POST. I'm using Javascript's built-in cloneNode(true) method to clone each line. The problem is that each input-line also has a removal link attached to its onclick-event:

// prototype based
<div class="input-line">
    <input .../>
    <a href="#" onclick="$(this).up().remove();"> Remove </a>
</div>

When the cloned input-line's removal link is clicked, it also removes any input-lines that were cloned from the same dom object. Is it possible to rebind the "this" object to the proper anchor tag after using cloneNode(true) on the above DOM element?

Upvotes: 5

Views: 8945

Answers (6)

Diego Perini
Diego Perini

Reputation:

First answer is the correct one.

Pornel is implicitly suggesting the most cross-browser and framework agnostic solution.

Haven't tested it, but the concept will work in these dynamic situations involving events.

Upvotes: 0

Kornel
Kornel

Reputation: 100170

Don't put handler on each link (this really should be a button, BTW). Use event bubbling to handle all buttons with one handler:

formObject.onclick = function(e)
{
    e=e||event; // IE sucks
    var target = e.target||e.srcElement; // and sucks again

    // target is the element that has been clicked
    if (target && target.className=='remove') 
    {
        target.parentNode.parentNode.removeChild(target.parentNode);
        return false; // stop event from bubbling elsewhere
    }
}

+

<div>
  <input…>
  <button type=button class=remove>Remove without JS handler!</button>
</div>

Upvotes: 7

J5.
J5.

Reputation: 356

To debug this problem, I would wrap your code

$(this).up().remove()

in a function:

function _debugRemoveInputLine(this) {
    debugger;
    $(this).up().remove();
}

This will allow you to find out what $(this) is returning. If it is indeed returning more than one object (multiple rows), then you definitely know where to look -- in the code which creates the element using cloneNode. Do you do any modification of the resulting element (i.e. changing the id attribute)?

If I had the problem you're describing, I would consider adding unique IDs to the triggering element and the "line" element.

Upvotes: 0

Greg
Greg

Reputation: 321796

I tested this in IE7 and FF3 and it worked as expected - there must be something else going on.

Here's my test script:

<div id="x">
    <div class="input-line" id="y">
        <input type="text">
        <a href="#" onclick="$(this).up().remove();"> Remove </a>
    </div>
</div>

<script>

$('x').appendChild($('y').cloneNode(true));
$('x').appendChild($('y').cloneNode(true));
$('x').appendChild($('y').cloneNode(true));

</script>

Upvotes: 0

doekman
doekman

Reputation: 19288

You could try cloning using the innerHTML method, or a mix:

var newItem = $(item).cloneNode(false);
newItem.innerHTML = $(item).innerHTML;

Also: I think cloneNode doesn't clone events, registered with addEventListener. But IE's attachEvent events are cloned. But I might be wrong.

Upvotes: 0

Fredrik Kalseth
Fredrik Kalseth

Reputation: 14224

Looks like you're using jQuery? It has a method to clone an element with events: http://docs.jquery.com/Manipulation/clone#true

EDIT: Oops I see you're using Prototype.

Upvotes: -1

Related Questions