Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.

Nested multifield in AEM 6.3 + sightly

Avatar

Level 2

Multifield dialog-

<?xml version="1.0" encoding="UTF-8"?>

<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"

    jcr:primaryType="nt:unstructured"

    jcr:title="List Collection"

    sling:resourceType="cq/gui/components/authoring/dialog">

    <content

        jcr:primaryType="nt:unstructured"

        sling:resourceType="granite/ui/components/coral/foundation/container">

        <items jcr:primaryType="nt:unstructured">

            <tabs

                jcr:primaryType="nt:unstructured"

                sling:resourceType="granite/ui/components/coral/foundation/tabs"

                maximized="{Boolean}true">

                <items jcr:primaryType="nt:unstructured">

                    <Basic

                        jcr:primaryType="nt:unstructured"

                        jcr:title="Basic"

                        sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"

                        margin="{Boolean}false">

                        <items jcr:primaryType="nt:unstructured">

                            <column

                                jcr:primaryType="nt:unstructured"

                                sling:resourceType="granite/ui/components/coral/foundation/container">

                                <items jcr:primaryType="nt:unstructured">

                                    <enterheadline

                                        jcr:primaryType="nt:unstructured"

                                        sling:resourceType="granite/ui/components/coral/foundation/form/textfield"

                                        fieldDescription="Please enter headline"

                                        fieldLabel="Enter Headline"

                                        name="./headlineText"/>

                                    <headingurl

                                        jcr:primaryType="nt:unstructured"

                                        sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"

                                        fieldDescription="Select Link Path"

                                        fieldLabel="Link Url"

                                        name="./headingUrl"/>

                                    <menu

                                        jcr:primaryType="nt:unstructured"

                                        sling:resourceType="granite/ui/components/foundation/form/multifield"

                                        composite="{Boolean}true"

                                        fieldDescription="Click + to add a new page"

                                        fieldLabel="Multifield collection"

                                        name="./menu">

                                        <field

                                            jcr:primaryType="nt:unstructured"

                                            sling:resourceType="granite/ui/components/foundation/form/fieldset"

                                            multifield-nested=""

                                            name="./items">

                                            <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">

                                                        <linkurl

                                                            jcr:primaryType="nt:unstructured"

                                                            sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"

                                                            fieldDescription="Select Link Path"

                                                            fieldLabel="Link Url"

                                                            name="./linkUrl"/>

                                                        <enterlinktext

                                                            jcr:primaryType="nt:unstructured"

                                                            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"

                                                            fieldDescription="Enter Link Text"

                                                            fieldLabel="Enter link text"

                                                            name="./linkText"/>

                                                        <submenu

                                                            jcr:primaryType="nt:unstructured"

                                                            sling:resourceType="granite/ui/components/foundation/form/multifield"

                                                            fieldDescription="Add upto 14 links"

                                                            fieldLabel="Submenus"

                                                            name="./submenussss">

                                                            <field

                                                                jcr:primaryType="nt:unstructured"

                                                                sling:resourceType="granite/ui/components/foundation/form/fieldset"

                                                                name="./submenu">

                                                                <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">

                                                                            <url

                                                                                jcr:primaryType="nt:unstructured"

                                                                                sling:resourceType="granite/ui/components/foundation/form/pathbrowser"

                                                                                allowBlank="false"

                                                                                fieldLabel="Provide navigation link for text"

                                                                                key="url"

                                                                                name="./subUrl"/>

                                                                            <title

                                                                                jcr:primaryType="nt:unstructured"

                                                                                sling:resourceType="granite/ui/components/foundation/form/textfield"

                                                                                allowBlank="false"

                                                                                fieldLabel="Provide navigation text"

                                                                                key="title"

                                                                                maxLength="16"

                                                                                maxLengthText="A maximum of 16 characters is allowed for navigation text"

                                                                                name="./subTitle"/>

                                                                        </items>

                                                                    </column>

                                                                </items>

                                                            </field>

                                                        </submenu>

                                                    </items>

                                                </column>

                                            </items>

                                        </field>

                                    </menu>

                                </items>

                            </column>

                        </items>

                    </Basic>

                </items>

            </tabs>

        </items>

    </content>

</jcr:root>

navigation.js

"use strict";

use(function () {

    var readJson = null;

    var listArr = [];

    if (this.fieldValue != '') {

        readJson = this.fieldValue;

        var count = 0;

        if (readJson != null && readJson != "") {

            readJson.forEach(function (entry) {

                var itemJson = entry;

                listArr[count++] = itemJson;

            });

        }

    } else if (this.fieldName != '') {

        readJson = granite.resource.properties[this.fieldName];

        if (typeof readJson != "undefined" && readJson != null && readJson != "") {

            if (readJson.length > 0) {

                var count = 0;

                readJson.forEach(function (entry) {

                    var itemJson = JSON.parse(entry);

                    listArr[count++] = itemJson;

                });

            } else {

                listArr[0] = JSON.parse(readJson);

            }

        }

    }

    return {

        listJson: listArr

    }

});

Sightly: somecomponent.html

<sly data-sly-use.menuInfo="${'navigation.js' @ fieldName = 'items',fieldValue = ''}">

                        <sly data-sly-list.menuDetails="${menuInfo.listJson}">

<li><a href="${menuDetails.linkUrl}">${menuDetails.linkText}</a>

<ul>

                                <sly data-sly-use.submenuInfo="${'navigation.js' @ fieldName = '',fieldValue = menuDetails.submenu}">

                                <sly data-sly-list.innerlistJson="${submenuInfo.listJson}">

${innerlistJson.subTitle}</span></a></li>

</sly>

                                </sly>

                                </ul>

</li>

</sly>

                        </sly>

I have created this without using ACS-common package. hope it will helpful for the community

8 Replies

Avatar

Level 4

the add button for multifield node which is menu

slingResourceType: granite/ui/components/foundation/form/multifield - add button not working

sling:resourceType="granite/ui/components/coral/foundation/form/multifield" - add button working but the Ok/Submit button not working

Avatar

Level 2

(function () {

  var DATA_NESTED = "data-multifield-nested";

  var CFFW = ".coral-Form-fieldwrapper";

  //reads multifield data from server, creates the nested composite multifields and fills them

  function addDataInFields() {

    $(document).on("dialog-ready", function () {

      var $fieldSets = $("[" + DATA_NESTED + "][class='coral-Form-fieldset']");

      if (_.isEmpty($fieldSets)) {

        return;

      }

      var mNames = [];

      $fieldSets.each(function (i, fieldSet) {

        mNames.push($(fieldSet).data("name"));

      });

      mNames = _.uniq(mNames);

      var actionUrl = $fieldSets.closest("form.foundation-form").attr("action") + ".json";

      $.ajax(actionUrl).done(postProcess);

      function postProcess(data) {

        _.each(mNames, function (mName) {

          buildMultiField(data, mName);

        });

      }

      //creates & fills the nested multifield with data

      function fillNestedFields($multifield, valueArr) {

        _.each(valueArr, function (record, index) {

          $multifield.find(".js-coral-Multifield-add").click();

          //a setTimeout may be needed

          _.each(record, function (value, key) {

            var $field = $($multifield.find("[name='./" + key + "']")[index]);

            $field.val(value);

          });

        });

      }

      function buildMultiField(data, mName) {

        if (_.isEmpty(mName)) {

          return;

        }

        $fieldSets = $("[data-name='" + mName + "']");

        mName = mName.substring(2);

        var mValues = data[mName], $field, name;

        if (_.isString(mValues)) {

          mValues = [JSON.parse(mValues)];

        }

        _.each(mValues, function (record, i) {

          if (!record) {

            return;

          }

          if (_.isString(record)) {

            record = JSON.parse(record);

          }

          _.each(record, function (rValue, rKey) {

            $field = $($fieldSets[i]).find("[name='./" + rKey + "']");

            if (_.isArray(rValue) && !_.isEmpty(rValue)) {

              fillNestedFields($($fieldSets[i]).find("[data-init='multifield']"), rValue);

            } else {

              $field.val(rValue);

            }

          });

        });

      }

    });

  }

  function fillValue($field, record) {

    var name = $field.attr("name");

    if (!name) {

      return;

    }

    //strip ./

    if (name.indexOf("./") === 0) {

      name = name.substring(2);

    }

    record[name] = $field.val();

    //remove the field, so that individual values are not POSTed

    //$field.remove();

  }

  //for getting the nested multifield data as js objects

  function getRecordFromMultiField($multifield) {

    var $fieldSets = $multifield.find("[class='coral-Form-fieldset']");

    var records = [], record, $fields, name;

    $fieldSets.each(function (i, fieldSet) {

      $fields = $(fieldSet).find("[name]");

      record = {};

      $fields.each(function (j, field) {

        fillValue($(field), record);

      });

      if (!$.isEmptyObject(record)) {

        records.push(record);

      }

    });

    return records;

  }

  //collect data from widgets in multifield and POST them to CRX as JSON

  function collectDataFromFields() {

    $(document).on("click", ".cq-dialog-submit", function () {

      var fieldd = $(".coral-Multifield");

      var sizee = fieldd.attr("data-minlinksallowed");

      if (sizee) {

        var uii = $(window).adaptTo("foundation-ui");

        var totalLinkCount = $(".coral-Multifield-list li").length;

        if (totalLinkCount < sizee) {

          uii.alert("Minimum " + sizee + " fields are required");

          return false;

        }

      }

      var $form = $(this).closest("form.foundation-form");

      $form.find('input.input-mf-data').each(function(){

        $(this).remove();

      });

      var $fieldSets = $("[" + DATA_NESTED + "][class='coral-Form-fieldset']");

      var record, $fields, $field, name, $nestedMultiField;

      $fieldSets.each(function (i, fieldSet) {

        $fields = $(fieldSet).children().children(CFFW);

        record = {};

        $fields.each(function (j, field) {

          $field = $(field);

          //may be a nested multifield

          $nestedMultiField = $field.find("[data-init='multifield']");

          if ($nestedMultiField.length === 0) {

            fillValue($field.find("[name]"), record);

          } else {

            name = $nestedMultiField.find("[class='coral-Form-fieldset']").data("name");

            if (!name) {

              return;

            }

            //strip ./

            name = name.substring(2);

            record[name] = getRecordFromMultiField($nestedMultiField);

          }

        });

        if ($.isEmptyObject(record)) {

          return;

        }

        //add the record JSON in a hidden field as string

          $('<input />').attr('type', 'hidden')

            .attr('class', 'input-mf-data')

            .attr('name', $(fieldSet).data("name"))

            .attr('value', JSON.stringify(record))

            .appendTo($form);

      });

      return true;

    });

  }

  $(document).ready(function () {

    addDataInFields();

    collectDataFromFields();

  });

  $(document).on("dialog-ready", function () {

    $(".js-coral-Multifield-add").click(function () {

      var field = $(this).parent();

      var size = field.attr("data-limit");

      if (size) {

        var ui = $(window).adaptTo("foundation-ui");

        var totalLinkCount = $(this).prev('ol').children('li').length;

        if (totalLinkCount >= size) {

          ui.alert("Warning", "Only " + totalLinkCount + " fields are allowed!", "notice");

          return false;

        }

      }

    });

  });

  //extend otb multifield for adjusting event propagation when there are nested multifields

  //for working around the nested multifield add and reorder

  CUI.MultifieldProject = new Class({

    toString: "Multifield",

    extend: CUI.Multifield,

    construct: function (options) {

      this.script = this.$element.find(".js-coral-Multifield-input-template:last");

    },

    _addListeners: function () {

      this.superClass._addListeners.call(this);

      //otb coral event handler is added on selector .js-coral-Multifield-add

      //any nested multifield add click events are propagated to the parent multifield

      //to prevent adding a new composite field in both nested multifield and parent multifield

      //when user clicks on add of nested multifield, stop the event propagation to parent multifield

      this.$element.on("click", ".js-coral-Multifield-add", function (e) {

        e.stopPropagation();

      });

      this.$element.on("drop", function (e) {

        e.stopPropagation();

      });

    }

  });

  CUI.Widget.registry.register("multifield", CUI.MultifieldProject);

})();

(function () {

  var DATA_NESTED = "data-multifield-nested";

  var CFFW = ".coral-Form-fieldwrapper";

  //reads multifield data from server, creates the nested composite multifields and fills them

  function addDataInFields() {

    $(document).on("dialog-ready", function () {

      var $fieldSets = $("[" + DATA_NESTED + "][class='coral-Form-fieldset']");

      if (_.isEmpty($fieldSets)) {

        return;

      }

      var mNames = [];

      $fieldSets.each(function (i, fieldSet) {

        mNames.push($(fieldSet).data("name"));

      });

      mNames = _.uniq(mNames);

      var actionUrl = $fieldSets.closest("form.foundation-form").attr("action") + ".json";

      $.ajax(actionUrl).done(postProcess);

      function postProcess(data) {

        _.each(mNames, function (mName) {

          buildMultiField(data, mName);

        });

      }

      //creates & fills the nested multifield with data

      function fillNestedFields($multifield, valueArr) {

        _.each(valueArr, function (record, index) {

          $multifield.find(".js-coral-Multifield-add").click();

          //a setTimeout may be needed

          _.each(record, function (value, key) {

            var $field = $($multifield.find("[name='./" + key + "']")[index]);

            $field.val(value);

          });

        });

      }

      function buildMultiField(data, mName) {

        if (_.isEmpty(mName)) {

          return;

        }

        $fieldSets = $("[data-name='" + mName + "']");

        mName = mName.substring(2);

        var mValues = data[mName], $field, name;

        if (_.isString(mValues)) {

          mValues = [JSON.parse(mValues)];

        }

        _.each(mValues, function (record, i) {

          if (!record) {

            return;

          }

          if (_.isString(record)) {

            record = JSON.parse(record);

          }

          _.each(record, function (rValue, rKey) {

            $field = $($fieldSets[i]).find("[name='./" + rKey + "']");

            if (_.isArray(rValue) && !_.isEmpty(rValue)) {

              fillNestedFields($($fieldSets[i]).find("[data-init='multifield']"), rValue);

            } else {

              $field.val(rValue);

            }

          });

        });

      }

    });

  }

  function fillValue($field, record) {

    var name = $field.attr("name");

    if (!name) {

      return;

    }

    //strip ./

    if (name.indexOf("./") === 0) {

      name = name.substring(2);

    }

    record[name] = $field.val();

    //remove the field, so that individual values are not POSTed

    //$field.remove();

  }

  //for getting the nested multifield data as js objects

  function getRecordFromMultiField($multifield) {

    var $fieldSets = $multifield.find("[class='coral-Form-fieldset']");

    var records = [], record, $fields, name;

    $fieldSets.each(function (i, fieldSet) {

      $fields = $(fieldSet).find("[name]");

      record = {};

      $fields.each(function (j, field) {

        fillValue($(field), record);

      });

      if (!$.isEmptyObject(record)) {

        records.push(record);

      }

    });

    return records;

  }

  //collect data from widgets in multifield and POST them to CRX as JSON

  function collectDataFromFields() {

    $(document).on("click", ".cq-dialog-submit", function () {

      var fieldd = $(".coral-Multifield");

      var sizee = fieldd.attr("data-minlinksallowed");

      if (sizee) {

        var uii = $(window).adaptTo("foundation-ui");

        var totalLinkCount = $(".coral-Multifield-list li").length;

        if (totalLinkCount < sizee) {

          uii.alert("Minimum " + sizee + " fields are required");

          return false;

        }

      }

      var $form = $(this).closest("form.foundation-form");

      $form.find('input.input-mf-data').each(function(){

        $(this).remove();

      });

      var $fieldSets = $("[" + DATA_NESTED + "][class='coral-Form-fieldset']");

      var record, $fields, $field, name, $nestedMultiField;

      $fieldSets.each(function (i, fieldSet) {

        $fields = $(fieldSet).children().children(CFFW);

        record = {};

        $fields.each(function (j, field) {

          $field = $(field);

          //may be a nested multifield

          $nestedMultiField = $field.find("[data-init='multifield']");

          if ($nestedMultiField.length === 0) {

            fillValue($field.find("[name]"), record);

          } else {

            name = $nestedMultiField.find("[class='coral-Form-fieldset']").data("name");

            if (!name) {

              return;

            }

            //strip ./

            name = name.substring(2);

            record[name] = getRecordFromMultiField($nestedMultiField);

          }

        });

        if ($.isEmptyObject(record)) {

          return;

        }

        //add the record JSON in a hidden field as string

          $('<input />').attr('type', 'hidden')

            .attr('class', 'input-mf-data')

            .attr('name', $(fieldSet).data("name"))

            .attr('value', JSON.stringify(record))

            .appendTo($form);

      });

      return true;

    });

  }

  $(document).ready(function () {

    addDataInFields();

    collectDataFromFields();

  });

  $(document).on("dialog-ready", function () {

    $(".js-coral-Multifield-add").click(function () {

      var field = $(this).parent();

      var size = field.attr("data-limit");

      if (size) {

        var ui = $(window).adaptTo("foundation-ui");

        var totalLinkCount = $(this).prev('ol').children('li').length;

        if (totalLinkCount >= size) {

          ui.alert("Warning", "Only " + totalLinkCount + " fields are allowed!", "notice");

          return false;

        }

      }

    });

  });

  //extend otb multifield for adjusting event propagation when there are nested multifields

  //for working around the nested multifield add and reorder

  CUI.MultifieldProject = new Class({

    toString: "Multifield",

    extend: CUI.Multifield,

    construct: function (options) {

      this.script = this.$element.find(".js-coral-Multifield-input-template:last");

    },

    _addListeners: function () {

      this.superClass._addListeners.call(this);

      //otb coral event handler is added on selector .js-coral-Multifield-add

      //any nested multifield add click events are propagated to the parent multifield

      //to prevent adding a new composite field in both nested multifield and parent multifield

      //when user clicks on add of nested multifield, stop the event propagation to parent multifield

      this.$element.on("click", ".js-coral-Multifield-add", function (e) {

        e.stopPropagation();

      });

      this.$element.on("drop", function (e) {

        e.stopPropagation();

      });

    }

  });

  CUI.Widget.registry.register("multifield", CUI.MultifieldProject);

})();

Avatar

Level 1

This solution is not working in  coral3 for aem6.3 migration. In coral 3 multifield tenplate is different so this js doesnt work.

Avatar

Community Advisor

Hi,

In Coral3, multifields items are store as a node not as JSON, To make it work this with Js or Java, you can iterate through nodes and return as JSON array or java Arraylist.



Arun Patidar

Avatar

Level 2

Using aem 6.3 service pack and cummulative fix pack, multiield of 'n' number of levels can be added in AEM 6.3.

  1. AEM 6.3 Cumulative Fix Pack (https://helpx.adobe.com/experience-manager/release-notes--aem-6-3-cumulative-fix-pack.html#DownloadI...)
  2. AEM 6.3.3.0 Service Pack (https://helpx.adobe.com/experience-manager/6-3/release-notes/sp3-release-notes.html#Install6330)