Tuesday, July 10, 2018
AEM 61 Touch UI Composite Multifield Store Values as Child Nodes
AEM 61 Touch UI Composite Multifield Store Values as Child Nodes
Goal
Create a Touch UI Composite Multifield, storing field values as child nodes (useful when executing search queries for exact matches).
For storing values as json check this post
For Classic UI Composite Multifield , storing values as child nodes check this post
For Touch UI Image Multifield check this post
Tested on AEM 61; should work ok on 60
Demo | Package Install
Bug Fixes
AEM 61 - Select granite/ui/components/foundation/form/select and Checkbox granite/ui/components/foundation/form/checkbox show incorrect values on dialog open - Demo | Package Install
AEM 60 SP2 - Select granite/ui/components/foundation/form/select and Checkbox granite/ui/components/foundation/form/checkbox show incorrect values on dialog open - Demo | Package Install
Composite Multifield in Dialog

Value Nodes in CRX

Dialog Structure

Dialog XML
Sample dialog with 3 composite multifields added in 3 tabs. #49, #125, #202 mark these multifields as composite, by specifying the flag eaem-nested
1) Login to CRXDE Lite, create folder (nt:folder) /apps/touch-ui-composite-multi-field-store-as-child-nodes
2) Create clientlib (type cq:ClientLibraryFolder) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib and set a property categories of String type to cq.authoring.dialog, dependencies of type String[] with value underscore
3) Create file ( type nt:file ) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib/js.txt, add the following
multifield.js
4) Create file ( type nt:file ) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib/multifield.js, add the following code
For storing values as json check this post
For Classic UI Composite Multifield , storing values as child nodes check this post
For Touch UI Image Multifield check this post
Tested on AEM 61; should work ok on 60
Demo | Package Install
Bug Fixes
AEM 61 - Select granite/ui/components/foundation/form/select and Checkbox granite/ui/components/foundation/form/checkbox show incorrect values on dialog open - Demo | Package Install
AEM 60 SP2 - Select granite/ui/components/foundation/form/select and Checkbox granite/ui/components/foundation/form/checkbox show incorrect values on dialog open - Demo | Package Install
Composite Multifield in Dialog

Value Nodes in CRX

Dialog Structure

Dialog XML
Sample dialog with 3 composite multifields added in 3 tabs. #49, #125, #202 mark these multifields as composite, by specifying the flag eaem-nested
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root
jcr_primaryType="nt:unstructured"
jcr_title="Multifield TouchUI Component"
sling_resourceType="cq/gui/components/authoring/dialog"
helpPath="en/cq/current/wcm/default_components.html#Text">
<content
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/tabs"
type="nav"/>
<items jcr_primaryType="nt:unstructured">
<india
jcr_primaryType="nt:unstructured"
jcr_title="India"
sling_resourceType="granite/ui/components/foundation/section">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<fieldset
jcr_primaryType="nt:unstructured"
jcr_title="India Dashboard"
sling_resourceType="granite/ui/components/foundation/form/fieldset">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<dashboard
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Dashboard name"
fieldLabel="Dashboard"
name="./iDashboard"/>
<pages
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/multifield"
class="full-width"
eaem-nested=""
fieldDescription="Click + to add a new page"
fieldLabel="URLs">
<field
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/fieldset"
name="./iItems">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
method="absolute"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<page
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Page Name"
fieldLabel="Page Name"
name="./page"/>
<path
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/pathbrowser"
fieldDescription="Select Path"
fieldLabel="Path"
name="./path"
rootPath="/content"/>
</items>
</column>
</items>
</field>
</pages>
</items>
</column>
</items>
</fieldset>
</items>
</column>
</items>
</india>
<usa
jcr_primaryType="nt:unstructured"
jcr_title="USA"
sling_resourceType="granite/ui/components/foundation/section">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<fieldset
jcr_primaryType="nt:unstructured"
jcr_title="USA Dashboard"
sling_resourceType="granite/ui/components/foundation/form/fieldset">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<dashboard
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Dashboard name"
fieldLabel="Dashboard"
name="./uDashboard"/>
<pages
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/multifield"
class="full-width"
eaem-nested=""
fieldDescription="Click + to add a new page"
fieldLabel="URLs">
<field
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/fieldset"
eaem-nested=""
name="./uItems">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
method="absolute"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<page
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Page Name"
fieldLabel="Page Name"
name="./page"/>
<path
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/pathbrowser"
fieldDescription="Select Path"
fieldLabel="Path"
name="./path"
rootPath="/content"/>
</items>
</column>
</items>
</field>
</pages>
</items>
</column>
</items>
</fieldset>
</items>
</column>
</items>
</usa>
<uk
jcr_primaryType="nt:unstructured"
jcr_title="UK"
sling_resourceType="granite/ui/components/foundation/section">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<fieldset
jcr_primaryType="nt:unstructured"
jcr_title="UK Dashboard"
sling_resourceType="granite/ui/components/foundation/form/fieldset">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<dashboard
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Dashboard name"
fieldLabel="Dashboard"
name="./ukDashboard"/>
<pages
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/multifield"
class="full-width"
eaem-nested=""
fieldDescription="Click + to add a new page"
fieldLabel="URLs">
<field
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/fieldset"
eaem-nested=""
name="./ukItems">
<layout
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
method="absolute"/>
<items jcr_primaryType="nt:unstructured">
<column
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/container">
<items jcr_primaryType="nt:unstructured">
<page
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/textfield"
fieldDescription="Enter Page Name"
fieldLabel="Page Name"
name="./page"/>
<path
jcr_primaryType="nt:unstructured"
sling_resourceType="granite/ui/components/foundation/form/pathbrowser"
fieldDescription="Select Path"
fieldLabel="Path"
name="./path"
rootPath="/content"/>
</items>
</column>
</items>
</field>
</pages>
</items>
</column>
</items>
</fieldset>
</items>
</column>
</items>
</uk>
</items>
</content>
</jcr:root>
Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/touch-ui-composite-multi-field-store-as-child-nodes
2) Create clientlib (type cq:ClientLibraryFolder) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib and set a property categories of String type to cq.authoring.dialog, dependencies of type String[] with value underscore
3) Create file ( type nt:file ) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib/js.txt, add the following
multifield.js
4) Create file ( type nt:file ) /apps/touch-ui-composite-multi-field-store-as-child-nodes/clientlib/multifield.js, add the following code
(function () {
var DATA_EAEM_NESTED = "data-eaem-nested";
var CFFW = ".coral-Form-fieldwrapper";
//reads multifield data from server, creates the nested composite multifields and fills them
function addDataInFields() {
function getMultiFieldNames($multifields){
var mNames = {}, mName;
$multifields.each(function (i, multifield) {
mName = $(multifield).children("[name$=@Delete]").attr("name");
mName = mName.substring(0, mName.indexOf("@"));
mName = mName.substring(2);
mNames[mName] = $(multifield);
});
return mNames;
}
function buildMultiField(data, $multifield, mName){
if(_.isEmpty(mName) || _.isEmpty(data)){
return;
}
_.each(data, function(value, key){
if(key == "jcr:primaryType"){
return;
}
$multifield.find(".js-coral-Multifield-add").click();
_.each(value, function(fValue, fKey){
if(fKey == "jcr:primaryType"){
return;
}
var $field = $multifield.find("[name=./" + fKey + "]").last();
if(_.isEmpty($field)){
return;
}
$field.val(fValue);
});
});
}
$(document).on("dialog-ready", function() {
var $multifields = $("[" + DATA_EAEM_NESTED + "]");
if(_.isEmpty($multifields)){
return;
}
var mNames = getMultiFieldNames($multifields),
$form = $(".cq-dialog"),
actionUrl = $form.attr("action") + ".infinity.json";
$.ajax(actionUrl).done(postProcess);
function postProcess(data){
_.each(mNames, function($multifield, mName){
buildMultiField(data[mName], $multifield, mName);
});
}
});
}
//collect data from widgets in multifield and POST them to CRX
function collectDataFromFields(){
function fillValue($form, fieldSetName, $field, counter){
var name = $field.attr("name");
if (!name) {
return;
}
//strip ./
if (name.indexOf("./") == 0) {
name = name.substring(2);
}
//remove the field, so that individual values are not POSTed
$field.remove();
$(<input />).attr(type, hidden)
.attr(name, fieldSetName + "/" + counter + "/" + name)
.attr(value, $field.val())
.appendTo($form);
}
$(document).on("click", ".cq-dialog-submit", function () {
var $multifields = $("[" + DATA_EAEM_NESTED + "]");
if(_.isEmpty($multifields)){
return;
}
var $form = $(this).closest("form.foundation-form"),
$fieldSets, $fields;
$multifields.each(function(i, multifield){
$fieldSets = $(multifield).find("[class=coral-Form-fieldset]");
$fieldSets.each(function (counter, fieldSet) {
$fields = $(fieldSet).children().children(CFFW);
$fields.each(function (j, field) {
fillValue($form, $(fieldSet).data("name"), $(field).find("[name]"), (counter + 1));
});
});
});
});
}
$(document).ready(function () {
addDataInFields();
collectDataFromFields();
});
})();