Goal
Create a Classic UI Nested Composite Multifield Panel. The logic for nested composite multifield and composite multifield is same; this post just has a copy of composite multifield code with additional dialog configuration required for nested multifield
For Touch UI Nested Composite Multifield, check this post
Demo | Package Install
Nested Composite Multifield
Values Stored in CRX as JSON
Dialog
Dialog as XML
#27 specifies the xtype multi-field-panel, for parent composite multifield, #60 the child composite multifield
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
title="Multi Field"
xtype="dialog">
<items
jcr:primaryType="cq:Widget"
xtype="tabpanel">
<items jcr:primaryType="cq:WidgetCollection">
<tab1
jcr:primaryType="cq:Panel"
title="Add">
<items jcr:primaryType="cq:WidgetCollection">
<map
jcr:primaryType="cq:Widget"
hideLabel="false"
name="./map"
title="Map"
xtype="multifield">
<fieldConfig
jcr:primaryType="cq:Widget"
border="true"
hideLabel="true"
layout="form"
padding="10px"
width="1000"
xtype="multi-field-panel">
<items jcr:primaryType="cq:WidgetCollection">
<product-year-value
jcr:primaryType="cq:Widget"
dName="year"
fieldLabel="Year"
width="60"
xtype="textfield"/>
<product-price-value
jcr:primaryType="cq:Widget"
dName="price"
fieldLabel="Price"
width="60"
xtype="textfield"/>
<product-version-value
jcr:primaryType="cq:Widget"
dName="version"
fieldLabel="Path to Version"
xtype="pathfield"/>
<product-region-multifield
jcr:primaryType="cq:Widget"
dName="region"
fieldLabel="Region"
hideLabel="false"
title="Add Regions"
xtype="multifield">
<fieldConfig
jcr:primaryType="cq:Widget"
border="true"
hideLabel="true"
layout="form"
padding="10px"
width="1000"
xtype="multi-field-panel">
<items jcr:primaryType="cq:WidgetCollection">
<product-country
jcr:primaryType="cq:Widget"
dName="country"
fieldLabel="Country"
width="60"
xtype="textfield"/>
<product-state
jcr:primaryType="cq:Widget"
dName="state"
fieldLabel="State"
width="60"
xtype="textfield"/>
</items>
</fieldConfig>
</product-region-multifield>
</items>
</fieldConfig>
</map>
</items>
</tab1>
</items>
</items>
</jcr:root>
Solution
1) Login to CRXDE Lite, create folder (nt:folder) /apps/classic-ui-nested-multi-field-panel
2) Create clientlib (type cq:ClientLibraryFolder) /apps/classic-ui-nested-multi-field-panel/clientlib and set a property categories of String type to cq.widgets
3) Create file ( type nt:file ) /apps/classic-ui-nested-multi-field-panel/clientlib/js.txt, add the following
multi-field.js
4) Create file ( type nt:file ) /apps/classic-ui-nested-multi-field-panel/clientlib/multi-field.js, add the following code
CQ.Ext.ns("ExperienceAEM");
ExperienceAEM.MultiFieldPanel = CQ.Ext.extend(CQ.Ext.Panel, {
panelValue: '',
constructor: function(config){
config = config || {};
ExperienceAEM.MultiFieldPanel.superclass.constructor.call(this, config);
},
initComponent: function () {
ExperienceAEM.MultiFieldPanel.superclass.initComponent.call(this);
this.panelValue = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.panelValue);
var dialog = this.findParentByType('dialog');
dialog.on('beforesubmit', function(){
var value = this.getValue();
if(value){
this.panelValue.setValue(value);
}
},this);
},
afterRender : function(){
ExperienceAEM.MultiFieldPanel.superclass.afterRender.call(this);
this.items.each(function(){
if(!this.contentBasedOptionsURL
|| this.contentBasedOptionsURL.indexOf(CQ.form.Selection.PATH_PLACEHOLDER) < 0){
return;
}
this.processPath(this.findParentByType('dialog').path);
})
},
getValue: function () {
var pData = {};
this.items.each(function(i){
if(i.xtype == "label" || i.xtype == "hidden" || !i.hasOwnProperty("dName")){
return;
}
pData[i.dName] = i.getValue();
});
return $.isEmptyObject(pData) ? "" : JSON.stringify(pData);
},
setValue: function (value) {
this.panelValue.setValue(value);
var pData = JSON.parse(value);
this.items.each(function(i){
if(i.xtype == "label" || i.xtype == "hidden" || !i.hasOwnProperty("dName")){
return;
}
i.setValue(pData[i.dName]);
});
},
validate: function(){
return true;
},
getName: function(){
return this.name;
}
});
CQ.Ext.reg("multi-field-panel", ExperienceAEM.MultiFieldPanel);