AEM Cloud Service - Composite Multifield in Content Fragments Editor

Goal

Adobe Experience Manager 2022.6.7904.20220629T070041Z-220600

For multiple configurable composite multifields in content fragments editor check this post

Create a Composite Multifield for Content Fragments Editor. Authors can edit the configuration of the multifield adding new fields or remove existing...

Demo | Package Install | CF Model | Github


Configure Composite MF


Multifield in Editor


Data Saved in CRX


Solution

1) Create the project eaem-cf-composite-mf

mvn -B org.apache.maven.plugins:maven-archetype-plugin:3.2.1:generate -D archetypeGroupId=com.adobe.aem 
-D archetypeArtifactId=aem-project-archetype -D archetypeVersion=36 -D aemVersion=cloud
-D appTitle="Experience AEM CS CF Composite Multifield" -D appId="eaem-cf-composite-mf" -D groupId="apps.experienceaem.assets"
-D frontendModule=none -D includeExamples=n -D includeDispatcherConfig=n


2) Create a helper thirdparty loadash client library /apps/eaem-cf-composite-mf/lodash with property categories="[eaem.lodash]"


3) For the keyValues composite multifield create a clientlib /apps/eaem-cf-composite-mf/clientlib-mf with categories="[dam.cfm.authoring.contenteditor.v2]" and dependencies="[eaem.lodash]". Add the following code..

(function ($) {
const URL = document.location.pathname,
CFFW = ".coral-Form-fieldwrapper",
MASTER = "master",
CFM_EDITOR_SEL = ".content-fragment-editor",
KV_MF_SELECTOR = "[data-granite-coral-multifield-name='keyValues']";
let initialized = false;

if( !isCFEditor() ){
return;
}

init();

function init(){
if(initialized){
return;
}

initialized = true;

window.Dam.CFM.Core.registerReadyHandler(() => {
extendRequestSave();

hideTabHeaders();

addKeyValueMultiFieldListener();

Dam.CFM.editor.UI.addBeforeApplyHandler( () => {
Dam.CFM.EditSession.notifyActiveSession();
Dam.CFM.EditSession.setDirty(true);
});
});
}

function hideTabHeaders(){
$("coral-tablist").last().hide();
}

function addKeyValueMultiFieldListener(){
const $kvMulti = $(KV_MF_SELECTOR);

createTemplateFromLastParkedTab();

Coral.commons.ready($kvMulti[0], splitKeyValueJSONIntoFields);
}

function splitKeyValueJSONIntoFields(kvMFField){
const $kvMFField = $(kvMFField),
kvMFName = $kvMFField.attr("data-granite-coral-multifield-name");

_.each(kvMFField.items.getAll(), function(item) {
const $content = $(item).find("coral-multifield-item-content");
let jsonData = $content.find("[name=" + kvMFName + "]").val();

if(!jsonData){
return;
}

jsonData = JSON.parse(jsonData);

$content.html(getParkedMFHtml());

fillMultiFieldItem(item, jsonData);
});
}

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

if(field == null){
return;
}

if(field.tagName === 'CORAL-DATEPICKER'){
field.valueAsDate = new Date(fValue);
}else{
field.value = fValue;
}
});
}

function createTemplateFromLastParkedTab(){
const $kvMulti = $(KV_MF_SELECTOR);

$kvMulti.find("template").remove();

let template = '<template coral-multifield-template=""><div>' + getParkedMFHtml() + '</div></template>';

$kvMulti.append(template);
}

function getParkedMFHtml(){
return $("coral-panel").last().find("coral-panel-content").html();
}

function getKeyValueData(){
const $kvMulti = $(KV_MF_SELECTOR),
kvMFName = $kvMulti.attr("data-granite-coral-multifield-name");
let kevValueData = [];

_.each($kvMulti[0].items.getAll(), function(item) {
const $fields = $(item.content).find("[name]"),
data = {};

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

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

kevValueData.push(JSON.stringify(data));
});

return { [ kvMFName] : kevValueData} ;
}

function canBeSkipped(field){
return (($(field).attr("type") == "hidden") || $(field).closest(CFFW).is(":hidden") ||!field.value);
}

function extendRequestSave(){
const CFM = window.Dam.CFM,
orignFn = CFM.editor.Page.requestSave;

CFM.editor.Page.requestSave = requestSave;

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

const kvData = getKeyValueData();

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

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

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

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

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

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

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

variation = variation || "master";

return variation;
}

function isCFEditor(){
return ((URL.indexOf("/editor.html") == 0)
|| (URL.indexOf("/mnt/overlay/dam/cfm/admin/content/v2/fragment-editor.html") == 0) )
}
}(jQuery));


4 comments:

  1. hi srrekant , its not working if i have two multifiled with diifrent name in a single cf , how to fix this ?

    ReplyDelete
    Replies
    1. https://experience-aem.blogspot.com/2023/06/aem-cloud-service-multiple-composite-multifields-in-content-fragment-editor.html

      Delete
  2. Hi Sreekanth,

    we have preview button for content fragment in Adobe Cloud Service . Can we implement same feature for on premises .
    The Feature is detailed in this doc.
    https://experienceleague.adobe.com/docs/experience-manager-learn/getting-started-with-aem-headless/how-to/preview.html?lang=en

    Thanks

    ReplyDelete
  3. Hi Sreekanth,

    I am having an issue when I refresh the content fragment multiple times (2-3 times), then check the crxde data, composite multifield json gets wiped. Any fix for it?

    ReplyDelete