AEM 6.1 Classic UI转Touch UI Multifield JS定制问题排查
Fixing Multifield Storage & Required Validation Issues in AEM Touch UI Dialog Conversion
Let's tackle your two key issues with converting the Classic UI multifield to Touch UI, using your existing JS code as a starting point.
1. Multifield Not Storing/Loading Values
Looking at your code, there are a few critical gaps in how you're handling data collection and population. Here's what's wrong and how to fix it:
Key Problems in Your Original Code:
- Incorrect Indexing: The
countervariable incollectDataFromFieldsstarts at 0, but you used(counter + 1)for array indexing—this creates mismatches when loading stored data later. - Field Traversal Bug: The selector
$(multifield).children().children(cmf.CFFW)doesn't reliably target inputs inside each multifield item, leading to missed fields. - Data Mapping Mismatch: The field naming pattern used during storage (
fieldSetName +"/" + name+"["+counter+"]") didn't align with the pattern used to load data (./"+mName+"/" + this.key), so values couldn't be mapped correctly.
Fixed Multifield Handling Code:
(function ($, $document) { "use strict"; var _ = window._, Class = window.Class; ACS.TouchUI.MultiCompositeMultiField = new Class({ toString: 'AARP Composite Multifield Store as Multi Value Field', extend: ACS.TouchUI.Widget, MULTI_VALUE_STORE: "MULTI_STORE", isMulti: false, CFFW: ".coral-Form-fieldwrapper", // Explicitly define field wrapper selector DATA_ACS_COMMONS_NESTED: "data-acs-commons-nested", // Define missing constant getMultiFieldNames: function(){ var cmf = this, mNames = {}, mName, $multifield, $template; $(".js-coral-Multifield-input-template").each(function (i, template) { $template = $(template); $multifield = $($template.html()); if(!cmf.isMultiValueStore($multifield.data(cmf.DATA_ACS_COMMONS_NESTED))){ return; } cmf.isMulti = true; // Fixed `this` reference to class instance mName = $multifield.data("name").substring(2); mNames[mName] = $template.closest(".coral-Multifield"); }); return mNames; }, buildMultiField: function(data, $multifield, mName){ var cmf = this; if(_.isEmpty(mName) || _.isEmpty(data)){ return; } var baseFieldName = "./" + mName + "/"; var dataLength = Array.isArray(data) ? data.length : 1; var currentItems = $multifield.find("li.coral-Multifield-input").length; // Add enough multifield items to match stored data length while(currentItems < dataLength){ $multifield.find(".js-coral-Multifield-add").click(); currentItems++; } // Populate each field with stored values _.each(data, function(item, index){ if(_.isObject(item)){ _.each(item, function(value, key){ if(key === "jcr:primaryType") return; var $field = $multifield.find("[name='"+baseFieldName + key +"']").eq(index); if(!_.isEmpty($field)){ cmf.setWidgetValue($field, value); } }); } }); }, addDataInFields: function () { var cmf = this, mNames = cmf.getMultiFieldNames(), $form = $("form.cq-dialog"); if(_.isEmpty(mNames)) return; var actionUrl = $form.attr("action") + ".infinity.json"; $.ajax(actionUrl).done(function(data){ _.each(mNames, function($multifield, mName){ cmf.buildMultiField(data[mName], $multifield, mName); }); $document.trigger("touchui-composite-multifield-nodestore-ready", mNames); }); }, getMultiValueStoreMultifields: function(){ return $("[" + this.DATA_ACS_COMMONS_NESTED + "='" + this.MULTI_VALUE_STORE + "']"); }, isMultiValueStore: function(name){ return (name === this.MULTI_VALUE_STORE); }, collectDataFromFields: function(){ if (!this.isMulti) return; var $multifields = this.getMultiValueStoreMultifields(); if(_.isEmpty($multifields)) return; var $form = $("form.cq-dialog"), cmf = this; $multifields.each(function(mfIndex, multifield){ var $mfItems = $(multifield).find("li.coral-Multifield-input"); $mfItems.each(function(itemIndex, item){ $(item).find(cmf.CFFW).find("[name]").each(function(j, field){ var $field = $(field); cmf.fillValue($form, $(multifield).data("name"), $field, itemIndex); }); }); }); }, fillValue: function($form, fieldSetName, $field, itemIndex){ var name = $field.attr("name"), value; if (!name) return; if (name.indexOf("./") === 0) { name = name.substring(2); } // Get value based on field type if (this.isCheckbox($field)) { value = $field.prop("checked") ? $field.val() : ""; } else if ($field.is("select")) { value = $field.val() || ""; } else { value = $field.val() || ""; } // Add hidden field with correct indexed name $('<input />').attr({ 'type': 'hidden', 'name': fieldSetName + "/" + name + "[" + itemIndex + "]", 'value': value }).appendTo($form); // Hide original field instead of removing it (preserves validation) $field.hide(); }, isCheckbox: function($field){ return $field.is("[type='checkbox']"); } }); $document.ready(function () { var compositeMultiField = new ACS.TouchUI.MultiCompositeMultiField(); $document.on("dialog-ready", function(){ compositeMultiField.addDataInFields(); }); // Handle submit with validation check $document.on("click", ".cq-dialog-submit", function(e){ var $form = $("form.cq-dialog"); // Trigger Coral UI's native validation var isValid = $form[0].checkValidity(); if(!isValid){ e.preventDefault(); // Highlight invalid fields and focus first error $form.addClass("coral-Form--invalid"); $form.find(":invalid").first().focus(); return; } // Collect data only if form is valid compositeMultiField.collectDataFromFields(); }); }); }(jQuery, jQuery(document)));
Key Multifield Fixes:
- Switched to zero-based indexing to match AEM's array storage pattern
- Improved field traversal to reliably target inputs in each multifield item
- Changed field removal to hiding, so validation can still access the original fields
- Aligned data loading and storage naming patterns for correct value mapping
2. Required Field Validation Not Working
The core issue here was that your original code removed input fields before validation ran, so Touch UI's Coral validation couldn't check the required Article Heading field. Here's how we fixed it:
Validation Fixes:
- Preserve Original Fields: Instead of removing fields in
fillValue, we hide them—this keeps them in the DOM so validation can check theirrequiredstatus. - Explicit Validation Check: Added a check in the submit handler using
$form[0].checkValidity()to trigger Coral's native validation. If the form is invalid, we prevent submission and highlight errors. - Conditional Data Collection: Only run
collectDataFromFieldsafter the form passes validation.
Additional Tips
- Ensure your Touch UI dialog's Article Heading field has the
required="{Boolean}true"attribute set in its XML definition - Use browser dev tools to check for JS errors—this will catch missing constants or selector issues quickly
- Verify that your base
ACS.TouchUI.Widgetclass definesDATA_ACS_COMMONS_NESTED(it should map todata-acs-commons-nested)
内容的提问来源于stack exchange,提问作者nikitha
相关产品推荐
相关产品推荐

