Skip to main content

Adobe

How To Extend Content Fragment Model Data Types

Who Knows What A Hacker Can Do With Your Information

Content as a Service has revolutionized content management systems in the delivery of content.  Content is created once, independent of channels, and delivered without additional custom application code.  This saves a lot of time in the creation and maintenance of content and reduces the cost of operation.

Adobe Experience Manager (AEM) has out-of-the-box (OOTB) features like Content Services, Assets HTTP API, and Content Fragment. These features help marketers create, maintain, and publish content for multiple channels like web pages, mobile apps, IoT devices, screens, and many more.

For understanding the basics of Content Fragments, please do read Working with Content Fragments.

The OOTB Content Fragment Data Types are basic widgets with specific UI behavior. For marketers, the basic behavior will not fulfill the authoring requirement.  Thankfully, AEM is flexible so we can extend the UI behavior of the basic data types with ease to create new data types.

Create Multi-Select Dropdown

In this blog, I am going to extend the Enumeration data type to create a new Multi-Select Dropdown data type.

Pic1

1. Overlay OOTB Enumeration Data Type

Overlay the OOTB Enumeration Data Type from libs (/libs/settings/dam/cfm/models/formbuilderconfig/datatypes/items) folder to apps (/apps/settings/dam/cfm/models/formbuilderconfig/datatypes/items) folder.  See the below image:

Pic2

2. Customize the Enumeration

After overlaying the OOTB node, change the node name to enumerationmultiselect.  Along with the default attributes present on the node, add tagsfield value in fieldProperties.  Tagsfield points to the OOTB /libs/dam/cfm/models/editor/components/datatypeproperties/tagsfields/tagsfields.jsp data type which provide multiple select behavior.  See the below image:

Pic3

3. Add Custom Behavior

The following steps add custom HTML to the generated DOM element which will be used to read and save the selected values in the multiselect.  To achieve this overlay /libs/dam/cfm/models/editor/components/datatypeproperties folder to /apps as shown in the below image:

Pic4

Create a JSP file uniqueidfield.jsp, below uniqueidfield folder, and add below code snippet.  The below code creates the hidden element to the HTML DOM element:

<%@ page import="org.apache.sling.api.resource.ValueMap" %>

<%

%><%@include file="/libs/granite/ui/global.jsp" %><%

%><%@ page session="false" contentType="text/html" pageEncoding="utf-8"%><%

    ValueMap fieldProperties = resource.adaptTo(ValueMap.class);

    String key = resource.getName();

    String xssKey = xssAPI.encodeForHTMLAttr(key);

%>

<input type="hidden" name="./content/items/<%= xssKey %>/granite:class" value="enumeration-multi-select">

 

Add the newly created datatype property to the enumerationmultiselect node in fieldProperties attribute as shown below image:

Pic5

4. Save Selected Values

By default, the values selected in the multi-select value will not be saved to the fragment.  To achieve this, we need to add custom JavaScript code.  In your custom application code, under the clientlibrary folder, add a new folder clientlib-author and add category dam.cfm.authoring.contenteditor.v2 as shown in the below image:

Pic6

Create a new JS file named enumerationmultiselect.js add it to the js.txt file under the clientlib-author folder.  Add the below code snippet to the JS file:

(function ($) {

    'use strict';

    var CFM,
        MASTER = "master",
        CFM_EDITOR_SEL = ".content-fragment-editor";

    $( window ).load(function() {
        if (window.Dam != undefined) {
            CFM = window.Dam.CFM;
            getEnumerationContent();
            var url = window.location.pathname;
            if(url.indexOf("/metadata-editor.html/") < 0) {
            extendRequestSave();
            }
        }
    });

    function getEnumerationContent() {
        if (CFM.EditSession != undefined) {
            var url = CFM.EditSession.fragment.urlBase + "/jcr:content/data.2.json";
            $.ajax(url).done(loadContentIntoEnumerationContentField);
        }
    }

    function loadContentIntoEnumerationContentField(data) {
        var coralSelect = $('#aem-cfm-editor-elements-form .enumeration-multi-select');
        $.each(coralSelect, function() {
            var name = $(this).attr('name');
            var selectValue = data.master[name].split(',');
            setSelectValue($(this), selectValue);
            var tagList = getTagList(selectValue);
            $(this).find('.coral3-Select-tagList').append(tagList);
        });
    }

    function setSelectValue(eachSelect, selectValue) {
        var selectedItem = $(eachSelect).find('coral-select-item');
        $.each(selectedItem, function() {
            var value = $(this).attr('value');
            if (selectValue.includes(value)) {
                $(this).attr('selected', "");
            }
        });
    }

    function getTagList(selectValue) {
        var html = "";
        $.each(selectValue, function(index, value) {
            html = html + "<coral-tag value=\"" + value + "\">" + value + "</coral-tag>";
        });
        return html;
    }

    function getVariation() {
        var variation = $(CFM_EDITOR_SEL).data('variation');
        variation = variation || "master";
        return variation;
    }

    function getFormData() {
        var coralSelect = $('#aem-cfm-editor-elements-form .enumeration-multi-select');
        var value = {};
        $.each(coralSelect, function() {
            var tags = $(this).find('.coral3-Select-tagList .coral3-Tag');
            var name = $(this).attr('name');
            var values = [];
            $.each(tags, function() {
                var tagValue = $(this).val();
                values.push(tagValue);
            });
            value[name] = values.join();
        });
        return value;
    }

    function extendRequestSave(){
        if (CFM.editor != undefined) {
            var originFn = CFM.editor.Page.requestSave;
            CFM.editor.Page.requestSave = requestSave;
            function requestSave(callback, options) {
                originFn.call(this, callback, options);
                var formData = getFormData();
                if(formData.length == 0){
                    return;
                }
                var url = CFM.EditSession.fragment.urlBase + ".cfm.content.json",
                    variation = getVariation(),
                    createNewVersion = (options && !!options.newVersion) || false;

                formData[":type"] = "multiple";
                formData[":newVersion"] = createNewVersion;
                formData["_charset_"] = "utf-8";
                if(variation !== MASTER){
                    formData[":variation"] = variation;
                }
                var request = {
                    url: url,
                    method: "post",
                    dataType: "json",
                    data: formData,
                    cache: false
                };

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

 

Create A Content Fragment Model

Now time to validate. Navigate to the Content Fragment Model console and you will see the new Enumeration Multi Select Data Type as showing in the below image:

Pic7

Create a simple model by adding the drag and dropping the new Enumeration Multi Select Data Type and then click Save.  With the new content fragment model, create a content fragment. We can then select multiple values from the enumeration.

The below video shows the behavior of the new Enumeration Multi-Select behavior on the content fragment.

Pic8

For more information on this topic and related items, you can also read the below blogs. The below blogs will provide more ideas to customize content fragment model data types:

Thoughts on “How To Extend Content Fragment Model Data Types”

  1. The component gets created and shows up in content fragment model creation but won’t appear when creating content fragment

  2. Rajat Gawali Post author

    I am afraid we cannot create a tab structure in content fragments. If you really want to do that, you might need to find a way to add a root panel that behaves like a tab structure.

  3. Rajat Gawali Post author

    The field doesn’t show in the created content fragment or the model is not appearing while creating a new content fragment. Which way it is?

  4. @Rajat, have you tried this in AEM 6.5 ? I followed the exact steps you suggested however overlaying /libs/dam/cfm/models/editor/components/datatypeproperties is not allowed in AEM 6.5. And I didn’t get about the tab structure you’re talking about.

    I mean to ask that when you use the multi select enumeration field in content fragment it just doesn’t show up the UI there like you have added in gif

  5. Rajat Gawali Post author

    @Shivam, I have it working in 6.5 but the customization was done in 6.4 and it still works in 6.5.

  6. @Rajat when I try to do the step Add Custom Behavior, it doesn’t let you overlay node so I manually created those folders and I followed rest all steps as shown however to me the Widget is not appearing.

    Also can you share the location where when doing the step:
    Create a new JS file named enumerationmultiselect.js add it to the js.txt file under the clientlib-author folder. Add the below code snippet to the JS file:
    you add these files in exactly which clientlib-author? Can you share the complete address for the same?

  7. Hi @Rajat, I followed your steps to create a multiple-select dropdown, it appears in Content Fragment Model Editor, however when I drag and drop it, the “Properties” tab at top-right became empty, after click “Save”, it disappeared.

    The “fieldProperties” are:
    labelfield
    maptopropertyfield
    optionsmultifield
    placeholderfield
    requiredfield
    uniquefield
    tagsfield
    /apps/dam/cfm/models/editor/components/datatypeproperties/uniqueidfield/uniqueidfield.jsp

    The 1st six properties are default. I am using AEM 6.5. I can send screenshots if there is a way.

    Any idea?

    Thanks

  8. Hi guys. For the ones who have the problem with the Properties not visible on the UI, you must add to the enumerationmultiselect node this property: fieldMetaTypes String[] enumerationmultiselect. The metatype must be the same like the node name. Unfortunately after this the multi select does still not work, and I was not able to figure it out why, and another strange thing is that the content fragment model created with this custom component is disappearing from time to time, so it’s unreliable. And unfortunately I don’t have any more time to spend on it, although it would have been great if it would have worked

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Rajat Gawali

Rajat Gawali is an AEM developer. He blogs to share his knowledge on Adobe Experience Manager and related topics.

More from this Author

Categories
Follow Us
TwitterLinkedinFacebookYoutubeInstagram