Question

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?

Was it helpful?

Solution

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>

OTHER TIPS

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.

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>

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top