Expand my Community achievements bar.

Elevate your expertise and be recognized as a true influencer! Nominations for the exclusive Adobe Community Advisor program 2023 are now OPEN.
SOLVED

Nested Multifield in Content Fragment - AEM 6.5 ?

Avatar

Level 6

I have implemented  multi-field  in content fragment and it working and there is no any issue.

Also, Implementing nested multi-field but somehow it is working but not working fully. Values are getting save at backend but when i open the content fragment there are no auto value rendering in CF.

Has anyone implemented it or written JS code for the same . Please let me know. Thank You..!!

1 Accepted Solution

Avatar

Correct answer by
Level 4

I have tried this once and had to do a lot of customization to get it working.

In your content fragment model, you need to make the change similar to this: ( i am just showing a part of CFM which I had made composite multifield.

<multifieldtest
	jcr:primaryType="nt:unstructured"
	sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
	composite="{Boolean}true"
	fieldLabel="Test Service"
	listOrder="1"
	maxlength="255"
	metaType="text-single"
	name="testSection"
	renderReadOnly="false"
	showEmptyInReadOnly="true"
	valueType="string[]">
	<field
		jcr:primaryType="nt:unstructured"
		sling:resourceType="granite/ui/components/coral/foundation/container"
		name="./testSection">
		<items jcr:primaryType="nt:unstructured">
			<column
				jcr:primaryType="nt:unstructured"
				sling:resourceType="granite/ui/components/coral/foundation/container">
				<items jcr:primaryType="nt:unstructured">
					<!-- your fields go heare -->
				</items>
			</column>
		</items>
	</field>
</multifieldtest>

After that, used the following code to populate the data into the fields:

(function ($) {
    var CFM = window.Dam.CFM,
        MASTER = "master",
        CFM_EDITOR_SEL = ".content-fragment-editor",
        CORAL_MF_ITEM = "coral-multifield-item",
        EAEM_COMPOSITE_ITEM_VALUE = "data-eaem-composite-item-value",
        MF_NAME_ATTR = "data-granite-coral-multifield-name",
        COMPOSITE_MF_SEL = "[data-granite-coral-multifield-composite]";

    CFM.Core.registerReadyHandler(getMultifieldsContent);

    extendRequestSave();

    function getMultifieldsContent(){
        if(!compositeMutifieldsExist()){
            return;
        }

        var url = CFM.EditSession.fragment.urlBase + "/jcr:content/data.2.json";

        $.ajax(url).done(loadContentIntoMultiFields);
    }

    function loadContentIntoMultiFields(data){
        var $composites = $(COMPOSITE_MF_SEL), mfValArr, mfAddEle,
            vData = data[getVariation()], $lastItem;

        if(_.isEmpty(vData)){
            return;
        }

        _.each($composites, function(mField){
            mfValArr = vData[getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))];

            if(_.isEmpty(mfValArr)){
                return;
            }

            mfAddEle = mField.querySelector("[coral-multifield-add]");

            _.each(mfValArr, function(mfMap){
                mfAddEle.click();

                $lastItem = $(mField).find(CORAL_MF_ITEM).last();
                $lastItem.attr(EAEM_COMPOSITE_ITEM_VALUE, mfMap);
                Coral.commons.ready($lastItem[0], function (lastItem) {
                    fillMultifieldItems(lastItem);
                });

            });
        });
    }

    function fillMultifieldItems(mfItem){
        if(mfItem == null){
            return;
        }

        var mfMap = mfItem.getAttribute(EAEM_COMPOSITE_ITEM_VALUE);

        if(_.isEmpty(mfMap)){
            return;
        }

        mfMap = JSON.parse(mfMap);

        _.each(mfMap, function(fValue, fKey){
            const field = mfItem.querySelector("[name$='" + fKey + "']");

            if(field == null){
                return;
            }

            setFieldValue(field, fValue);
        });
    }

    function setFieldValue(field, value){
        if( field.tagName == "CORAL-CHECKBOX"){
            field.checked = (field.getAttribute("value") == value);
        }else{
            field.value = value;
        }
    }

    function getVariation(){
        var variation = $(CFM_EDITOR_SEL).data('variation');

        variation = variation || "master";

        return variation;
    }

    function compositeMutifieldsExist(){
        return !_.isEmpty($(COMPOSITE_MF_SEL));
    }

    function extendRequestSave(){
        var orignFn = CFM.editor.Page.requestSave;

        CFM.editor.Page.requestSave = requestSave;

        function requestSave(callback, options) {
            orignFn.call(this, callback, options);

            if(!compositeMutifieldsExist()){
                return;
            }

            var mfsData = getMultifieldData();

            if(_.isEmpty(mfsData)){
                return;
            }

            var url = CFM.EditSession.fragment.urlBase + ".cfm.content.json",
                variation = getVariation(),
                createNewVersion = (options && !!options.newVersion) || false;

            var data = {
                ":type": "multiple",
                ":newVersion": createNewVersion,
                "_charset_": "utf-8"
            };

            if(variation !== MASTER){
                data[":variation"] = variation;
            }

            var request = {
                url: url,
                method: "post",
                dataType: "json",
                data: _.merge(data, mfsData),
                cache: false
            };

            CFM.RequestManager.schedule({
                request: request,
                type: CFM.RequestManager.REQ_BLOCKING,
                condition: CFM.RequestManager.COND_EDITSESSION,
                ui: (options && options.ui)
            })
        }
    }

    function getMultifieldData(){
        var $composites = $(COMPOSITE_MF_SEL), value,
            mfData = {}, values, $fields;

        _.each($composites, function(mField){
            values = [];

            _.each(mField.items.getAll(), function(item) {
                $fields = $(item.content).find("[name]");

                value = {};

                _.each($fields, function(field){
                    if(canbeSkipped(field)){
                        return;
                    }

                    value[getNameDotSlashRemoved(field.getAttribute("name"))] =  getFieldValue(field);
                });

                values.push(JSON.stringify(value));
            });

            mfData[ getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))] = values;
        });

        return mfData;
    }

    function getFieldValue(field){
        var value;

        if( field.tagName == "CORAL-CHECKBOX"){
            value = field.checked ? field.getAttribute("value") : "";
        }else{
            value = field.value;
        }

        return value;
    }

    function canbeSkipped(field){
        return (($(field).attr("type") == "hidden") || (field.type == "checkbox"));
    }

    function getNameDotSlashRemoved(name){
        if(_.isEmpty(name)){
            return name;
        }

        const indexOfLastSlash = name.lastIndexOf("/");
		return (indexOfLastSlash === -1) ? name : name.substr(indexOfLastSlash + 1);
    }
}(jQuery));
14 Replies

Avatar

Level 6

@Asutosh_Jena_ Thanks Ashutosh for reply. Multifield i have already implemented in CF. I am looking for nested multifield in content fragment that is somehow working but not fully. For that we need to write the custom js code, I need that. Thanks

Avatar

Level 6

@Kishore_Kumar_ Thanks Kishor. I have already implemented multifield in component but  I need to implement in Content Fragment not in component. Thanks

Avatar

Community Advisor

Oh ok my bad sorry. I haven't tried customizing CF for nested multifield capability in 6.5. But if you can share us some sample code what you have achieved so far, me/someone may help to fix.

 

 

Avatar

Level 5

This is what you can try:

  • Add a content reference multifield in the first content fragment model.
  • Create a 2nd content fragment model and again add a multifield of required type there.
  • Reference the content fragments of second type from the first type

I think this would be the simpliest way to achieve this. May me you can try customizing as given in the links shared here in previous comments depending on your requirement. 

Avatar

Level 6

@ibishika I have already implemented nested multi field in Content fragment but it is not working fully. Have u implemented it ??

Avatar

Administrator

@ibishika  Good to see you back inside the AEM Community. Keep the great work of assisting others going. Looking forward to more contributions from you. 

Avatar

Level 1

@ibishika can you help me in referencing one content fragment with another?

Avatar

Correct answer by
Level 4

I have tried this once and had to do a lot of customization to get it working.

In your content fragment model, you need to make the change similar to this: ( i am just showing a part of CFM which I had made composite multifield.

<multifieldtest
	jcr:primaryType="nt:unstructured"
	sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
	composite="{Boolean}true"
	fieldLabel="Test Service"
	listOrder="1"
	maxlength="255"
	metaType="text-single"
	name="testSection"
	renderReadOnly="false"
	showEmptyInReadOnly="true"
	valueType="string[]">
	<field
		jcr:primaryType="nt:unstructured"
		sling:resourceType="granite/ui/components/coral/foundation/container"
		name="./testSection">
		<items jcr:primaryType="nt:unstructured">
			<column
				jcr:primaryType="nt:unstructured"
				sling:resourceType="granite/ui/components/coral/foundation/container">
				<items jcr:primaryType="nt:unstructured">
					<!-- your fields go heare -->
				</items>
			</column>
		</items>
	</field>
</multifieldtest>

After that, used the following code to populate the data into the fields:

(function ($) {
    var CFM = window.Dam.CFM,
        MASTER = "master",
        CFM_EDITOR_SEL = ".content-fragment-editor",
        CORAL_MF_ITEM = "coral-multifield-item",
        EAEM_COMPOSITE_ITEM_VALUE = "data-eaem-composite-item-value",
        MF_NAME_ATTR = "data-granite-coral-multifield-name",
        COMPOSITE_MF_SEL = "[data-granite-coral-multifield-composite]";

    CFM.Core.registerReadyHandler(getMultifieldsContent);

    extendRequestSave();

    function getMultifieldsContent(){
        if(!compositeMutifieldsExist()){
            return;
        }

        var url = CFM.EditSession.fragment.urlBase + "/jcr:content/data.2.json";

        $.ajax(url).done(loadContentIntoMultiFields);
    }

    function loadContentIntoMultiFields(data){
        var $composites = $(COMPOSITE_MF_SEL), mfValArr, mfAddEle,
            vData = data[getVariation()], $lastItem;

        if(_.isEmpty(vData)){
            return;
        }

        _.each($composites, function(mField){
            mfValArr = vData[getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))];

            if(_.isEmpty(mfValArr)){
                return;
            }

            mfAddEle = mField.querySelector("[coral-multifield-add]");

            _.each(mfValArr, function(mfMap){
                mfAddEle.click();

                $lastItem = $(mField).find(CORAL_MF_ITEM).last();
                $lastItem.attr(EAEM_COMPOSITE_ITEM_VALUE, mfMap);
                Coral.commons.ready($lastItem[0], function (lastItem) {
                    fillMultifieldItems(lastItem);
                });

            });
        });
    }

    function fillMultifieldItems(mfItem){
        if(mfItem == null){
            return;
        }

        var mfMap = mfItem.getAttribute(EAEM_COMPOSITE_ITEM_VALUE);

        if(_.isEmpty(mfMap)){
            return;
        }

        mfMap = JSON.parse(mfMap);

        _.each(mfMap, function(fValue, fKey){
            const field = mfItem.querySelector("[name$='" + fKey + "']");

            if(field == null){
                return;
            }

            setFieldValue(field, fValue);
        });
    }

    function setFieldValue(field, value){
        if( field.tagName == "CORAL-CHECKBOX"){
            field.checked = (field.getAttribute("value") == value);
        }else{
            field.value = value;
        }
    }

    function getVariation(){
        var variation = $(CFM_EDITOR_SEL).data('variation');

        variation = variation || "master";

        return variation;
    }

    function compositeMutifieldsExist(){
        return !_.isEmpty($(COMPOSITE_MF_SEL));
    }

    function extendRequestSave(){
        var orignFn = CFM.editor.Page.requestSave;

        CFM.editor.Page.requestSave = requestSave;

        function requestSave(callback, options) {
            orignFn.call(this, callback, options);

            if(!compositeMutifieldsExist()){
                return;
            }

            var mfsData = getMultifieldData();

            if(_.isEmpty(mfsData)){
                return;
            }

            var url = CFM.EditSession.fragment.urlBase + ".cfm.content.json",
                variation = getVariation(),
                createNewVersion = (options && !!options.newVersion) || false;

            var data = {
                ":type": "multiple",
                ":newVersion": createNewVersion,
                "_charset_": "utf-8"
            };

            if(variation !== MASTER){
                data[":variation"] = variation;
            }

            var request = {
                url: url,
                method: "post",
                dataType: "json",
                data: _.merge(data, mfsData),
                cache: false
            };

            CFM.RequestManager.schedule({
                request: request,
                type: CFM.RequestManager.REQ_BLOCKING,
                condition: CFM.RequestManager.COND_EDITSESSION,
                ui: (options && options.ui)
            })
        }
    }

    function getMultifieldData(){
        var $composites = $(COMPOSITE_MF_SEL), value,
            mfData = {}, values, $fields;

        _.each($composites, function(mField){
            values = [];

            _.each(mField.items.getAll(), function(item) {
                $fields = $(item.content).find("[name]");

                value = {};

                _.each($fields, function(field){
                    if(canbeSkipped(field)){
                        return;
                    }

                    value[getNameDotSlashRemoved(field.getAttribute("name"))] =  getFieldValue(field);
                });

                values.push(JSON.stringify(value));
            });

            mfData[ getNameDotSlashRemoved(($(mField)).attr(MF_NAME_ATTR))] = values;
        });

        return mfData;
    }

    function getFieldValue(field){
        var value;

        if( field.tagName == "CORAL-CHECKBOX"){
            value = field.checked ? field.getAttribute("value") : "";
        }else{
            value = field.value;
        }

        return value;
    }

    function canbeSkipped(field){
        return (($(field).attr("type") == "hidden") || (field.type == "checkbox"));
    }

    function getNameDotSlashRemoved(name){
        if(_.isEmpty(name)){
            return name;
        }

        const indexOfLastSlash = name.lastIndexOf("/");
		return (indexOfLastSlash === -1) ? name : name.substr(indexOfLastSlash + 1);
    }
}(jQuery));

Avatar

Level 6

@prashantonkar : Thanks for reply. I have tested multi-field the same way and it is working as expected in the Content Fragment.

 

But my question is related to nested-multi field.I think the code that you shared it seems its for multifield.

JS code that you shared so is it for multifield or nested-multifield???

 

Thank You.

Avatar

Level 2

Hi @kchaurasiya,

 

Have you found any solution for the scenario you mentioned above, if so kindly share the solution so that we can try from our side.

 

Thank you

Avatar

Level 2

Instead of using the following sling:resourceType , 

sling:resourceType
granite/ui/components/coral/foundation/form/multifield
granite/ui/components/foundation/form/multifield


use the resourceType : dam/cfm/admin/components/authoring/contenteditor/cfmmultifield