AEM 6 - Attaching Listeners to Asset Metadata Editor Form Fields

Goal


Create a new Asset Metadata Editor Form field and attach Listeners

This post demonstrates adding a new form field to Asset metadata editor using the Metadata Schema feature of AEM 6

Demo | Package Install

Thank you Dave Chang for the PredicateBuilder logic


listeners node added under Serial metadata form field node




keypress listener shows error tooltip when user types-in a space



Solution


1) Add a new form field to Image asset metadata editor by accessing the Metadata schema form of image (http://localhost:4502/libs/dam/gui/content/metadataschemaeditor/schemadetails.html/dam/content/schemaeditors/forms/default/image)

2) Add a new form field Serial with property ./jcr:content/metadata/serial



3) Click done and the form field node can be found under /apps/dam/content/schemaeditors/forms/default/image in CRXDE Lite (http://localhost:4502/crx/de). In my CQ the node got created at /apps/dam/content/schemaeditors/forms/default/image/items/tabs/items/tab1/items/col2/items/1418939382969

4) Add a new node listeners of type nt:unstructured with property

                       Name: keypress
                       Type: String
                       Value: function(event) { ExperienceAEM.textOnly(event) }




5) The keypress event function attached to editor form field Serial executes when user keys-in any character. The javascript function ExperienceAEM.textOnly added in next steps checks for whitespace and shows error tooltip if user tries to enter spaces

6) In CRXDE Lite (http://localhost:4502/crx/de) create folder /apps/touch-ui-metadata-listeners

7) Create node /apps/touch-ui-metadata-listeners/clientlib of type cq:ClientLibraryFolder and add a String property categories with value dam.gui.metadataeditor

8) Create file (nt:file) /apps/touch-ui-metadata-listeners/clientlib/js.txt and add

             attach-listeners.js
             text-only.js

9) Create file (nt:file) /apps/touch-ui-metadata-listeners/clientlib/attach-listeners.js and add the following code. Here we are reading form fields, querying CRX for any listener nodes and attach event listeners. This is sample code for adding listeners on input elements and not guaranteed to work on every metadata editor element. Based on the form field element type (say select) the code needs to be adjusted...

(function(document, $) {
    "use strict";

    var SCHEMA_EDITOR_PATH = "/apps/dam/content/schemaeditors";
    var QUERY_BUILDER = "/bin/querybuilder.json";
    var NODE_LISTENERS = "listeners";
    var SEARCH_TEXT_IN_LISTENERS = "function";

    function PredicateBuilder(defaults) {
        this.params = $.extend({}, defaults);
        this.numPredicates = 0;
    }

    PredicateBuilder.prototype = {
        fullText: function(value, relPath) {
            if (!value) {
                return this;
            }

            this.params[this.numPredicates + '_fulltext'] = value;

            if (relPath) {
                this.params[this.numPredicates + '_fulltext.relPath'] = relPath;
            }

            this.numPredicates++;

            return this;
        },

        prop: function(name, value) {
            if (name && value) {
                this.params[this.numPredicates + '_property'] = name;

                if($.isArray(value)) {
                    var that = this;

                    $.each(value, function(i, item) {
                        that.params[that.numPredicates + '_property.' + i + '_value'] = item;
                    });
                }else{
                    this.params[this.numPredicates + '_property.value'] = value;
                }

                this.numPredicates++;
            }

            return this;
        },

        http: function(){
            var builder = this;

            return $.ajax({
                method: 'GET',
                url: QUERY_BUILDER,
                data: builder.params
            });
        }
    };

    var attachListeners = function(hits){
        if(!$.isArray(hits)){
            return;
        }

        var $ele;

        $.each(hits, function(i, hit){
            $ele = $("[name='" + hit["name"] + "']");

            $.each(hit.listeners, function(key, value){
                if(key == "jcr:primaryType"){
                    return;
                }

                try{
                    $ele.on(key, eval("(" + value+ ")" ) );
                }catch(err){
                    console.log("Error attaching listener : " + key + " - " + value);
                }
            })
        });
    };

    $(document).on("foundation-contentloaded", function(e) {
        var $editables = $(".foundation-field-edit");

        if($editables.length == 0 ){
            return;
        }

        var builder = new PredicateBuilder({
            'path': SCHEMA_EDITOR_PATH,
            'p.hits': 'full',
            'p.nodedepth': 2,
            'p.limit': 100
        });

        var values = [];

        $editables.find("input").each(function(i, value){
            values.push($(value).attr("name"));
        });

        builder.prop("name", values).fullText(SEARCH_TEXT_IN_LISTENERS, NODE_LISTENERS)
                .http().done(function(resp) {
                    attachListeners(resp.hits);
                });
    });
})(document, Granite.$);

10) Add the event listener fired on keypress (added in a different js file). Create file (nt:file) /apps/touch-ui-metadata-listeners/clientlib/text-only.js and add the following code

(function() {
    if (typeof window.ExperienceAEM == "undefined") {
        window.ExperienceAEM = {};
    }

    var tooltip = null;

    ExperienceAEM.textOnly = function(event){
        if(!tooltip){
            tooltip = new CUI.Tooltip({
                type: "error",
                target: event.target,
                content: "No spaces allowed",
                visible:false,
                arrow: "left",
                interactive: false
            });
        }

        if(event.which === 32){
            tooltip.show();
            event.preventDefault();
        }else{
            tooltip.hide();
        }
    }
}());


1 comment:

  1. Hi,

    I am trying this in AEM 6.4 and it is not working. Can you please help?

    Thanks

    ReplyDelete