Recently, I had the need to be able to asynchronously duplicate portions of a form, arbitrarily based on what the user might want to do. The requirements were such that the script needed to be reusable multiple times per page. After having read the book DHTML Utopia by Stuart Langridge, I knew that something along the lines of his free beer example would be needed.
innerHTML dump would keep it confined in the
So, I thought the
cloneNode method might be a better way to go. Initially, after some searching around, I happened upon the solution offered on Quirksmode, Extending Forms. He has a clever way of doing it, with an invisible template, so to speak. This is cloned and set to
display: block so that the subsequent duplicates are usable. It also uses an empty
span with an ID as the insertion point in the document. It increments a counter so ID / name will stay unique within the form, lest duplicate data be submitted.
This was the launching point for my idea. Yet, I wanted something more modular and reusable, without the need for unusable hidden templates or extraneous
span's. I believe that what I have come up with is a nice plug-and-play method. Essentially, it looks for the nearest parent
fieldset, clones it, adds a suffix + counter, then inserts the copy after the original.
The initial fieldset contains both an Add and Delete button, with deletion hidden by CSS. When the copy is made, a class of
duplicate is added, causing the Delete button to appear, and the Add button to disappear. I also use it to re-color the fieldset, giving a visual indicator of the cloning.
You might notice that the clone and delete functions are called directly with an
onclick event. Before you harp on that being too intrusive, I should mention that it was done this way because traversing through to find class names didn't account for the elements created after page load. So, rather than iterate through during each cloning, I went for the quicker route of just cloning the function call to
deleteMe() in the fieldset itself.
:N (with N being the counter) is found, and then stripped out, so a new counter can be added. That way, if you don't end up with the problem of
foo23. I chose the delimiter of [
:] because it is valid as part of an ID / name in XHTML, while still being unlikely enough not to conflict with any typical naming scheme using underscores or dashes.
I'm sure it can probably be improved upon, and that is of course why I'm releasing it - so that it can be a starting point for others faced with similar problems to solve. I want to thank Ara Pehlivanian for helping make the script self-referential, and Jonathan Snook for his ideas on incrementing a counter for nested fieldsets. Also, thanks to Jeremy Keith for his
insertAfter method, described in his book DOM Scripting. I guess that wraps it up!