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

<?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.dialogdependencies 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();
});
})();




visit link download