Cloning form elements in Internet Explorer
So, I ran into an issue when cloning form elements. The scenario was as follows: For an insurance company, a customer was reporting that a damage had occurred to one or more insured items. After adding general information about the event (it happened at such and such a date, while riding a bicycle), the customer added multiple items of goods that was damaged during the event. As a part of the damage goods part of the form, was a dropdown:
Report a damage Date: What happened? What was damaged? A ...
The idea was, that clicking the button would duplicate a part of the form, which would effectively increase the collection of block items in the associated view model:
public class ReportViewModel { public List<BlockViewModel> Blocks { get; set; } } public class BlockViewModel { public string Title { get; set; } public List<QuestionViewModel> Questions { get; set; } }
The solution worked pretty flawlessly too! For completeness, I wrote the following JavaScript helper methods to update the cloned objects' IDs:
function adjustIds(inSet, by) { inSet.each(function () { var div = $(this); increaseAttr(div, "data-item-index", 1); if (div.hasClass("field")) { increaseAttr(div.find("div.editor-label label"), "for", by); div.find("div.editor-field").each(function () { var editorField = $(this); increaseAttr(editorField.find("select, textarea, input, label"), ["name", "id", "for"], by); increaseAttr(editorField.find("span"), "data-valmsg-for", by); increaseAttr(editorField.find("div a"), "id", by); }); } } function increaseAttr(elements, attr, by) { if (Object.prototype.toString.call(attr) !== '[object Array]') attr = [attr]; $.each(elements, function () { var element = $(this); for (var i = 0; i < attr.length; i++) { var attributeValue = element.attr(attr[i]); if (typeof attributeValue !== 'undefined' && attributeValue !== false) { element.attr(attr[i], incrementFirstInteger(attributeValue, by)); } } }); } function incrementFirstInteger(str, by) { if (!by) by = 1; var pattern = /\d+/; var id = parseInt(str.match(pattern)) + by; return str.replace(pattern, id); }
However, cloning the select elements, caused some weird behavior - the first cloned select would never retain its value! See various posts around this issue on the web.
To work around the issue, I finally found the following solution, effectively replacing the cloned select elements with new, near-identical, copies (the near-identical is essential, since copying *all* attributes, for example, would render the copy as useless as the clone):
$("#clone-button").click(function() { ... var set = parent.find("div.child:last"); var newSet = $(set.clone(true)); newSet.find("select").replaceWith(function() { var str = "<select name=\"" + this.name + "\">"; $(this).find("option").each(function(){ str += this.outerHTML; }); return str + "</select>"; }); ... adjustIds(...); ... });
So, when cloning forms containing selects, if you run into issues, replace the cloned selects with new instances.
Have a nice day!
Comments