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:

About the Author

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

More from this Author

Leave a Reply

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

Subscribe to the Weekly Blog Digest:

Sign Up
Categories