views:

3958

answers:

6

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?

A: 

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.

Fredrik Kalseth
A: 

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.

doekman
A: 

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>
Greg
A: 

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.

J5
+5  A: 

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>
porneL
A: 

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.