user1032531
user1032531

Reputation: 26281

How to clone elements and their associated event callbacks?

I am cloning an element and adding it to the DOM. I expected that this within the newly created cloned element would refer to itself, but it appears to refer to the original clone element.

To illustrate, I created the following script. By clicking "cloneIt", a new element is added, and upon clicking the new element, this refers to the original clone. My desire was for data('type') to display "added".

How do I clone an element and have the callback pertain to the newly cloned object?

https://stackoverflow.com/

$('.fileupload').fileupload({
    start: function (e, data) {
        console.log('start', this, $(this).parent().data('type'));
    }
})
    .on('fileuploadsubmit', function (e, data) {
    console.log('fileuploadsubmit', this, $(this).parent().data('type'));
});

$('#cloneIt').click(function () {
    $('#clone').clone(true).removeAttr('id').data('type', 'added').appendTo('#container');
});

#clone {
    display:none;
}

<button id="cloneIt">cloneIt</button>
<ul id="container">
    <li id="clone" data-type="clone">
        <input class="fileupload" name="file" type="file" />
    </li>
    <li data-type="existing">
        <input class="fileupload" name="file" type="file" />
    </li>
</ul>

Upvotes: 3

Views: 421

Answers (2)

Roamer-1888
Roamer-1888

Reputation: 19288

It would appear that the start callback's notion of this gets locked in when .fileupload() is invoked, and that this is carried forward to the clone.

Personally I would keep the template LI separate from the live LIs, and never invoke .fileupload() on it.

HTML

<button id="cloneIt">cloneIt</button>
<ul id="template">
    <li data-type="original">
        <input class="fileupload" name="file" type="file" />
    </li>
</ul>
<ul id="container">
    <li data-type="existing">
        <input class="fileupload" name="file" type="file" />
    </li>
</ul>

CSS

#template {
    display:none;
}

Initially, invoke .fileupload() only on the INPUTs in #container, and subsequently on any clone of the template after it is made.

Javascript

$('#container .fileupload').fileupload({
    start: function (e, data) {
        console.log('start', this, $(this).parent().data('type'));
    }
}).on('fileuploadsubmit', function (e, data) {
    console.log('fileuploadsubmit', this, $(this).parent().data('type'));
});

$('#cloneIt').click(function () {
    $('#template li').clone().data('type', 'clone').appendTo('#container').find('.fileupload').fileupload(...);
});

I would recommend this approach with any plugin. Cloning a widgetized element is dangerous. Clone behaviour is not guaranteed to be reliable. With some plugins, you may get away with it; with others, you won't.

Upvotes: 2

Niloct
Niloct

Reputation: 9995

http://jsfiddle.net/1as47aeb/5/

Seems like you need to call the fileupload method from the library again, after creating the DOM object.

If you inspect the DOM in your code, you will see that the attribute is there, added, and you can query it inside your original code after cloning.

EDIT

Corrected behavior in which both input events called when uploading in clone input.

Upvotes: 1

Related Questions