AEM 62 - Support Required (Validator) on FileUpload (Image) in Touch UI Dialog

Goal


Touch UI extension to support required on FileUpload widget - /libs/granite/ui/components/foundation/form/fileupload using Granite validator. For validation api check documentation

For a similar extension on 61 supporting required on RTE check this post

Dialog of foundation image component /libs/foundation/components/image/cq:dialog/content/items/column/items/file was modified for demonstration purposes only

Demo | Package Install


File Upload widget - required = true



Validation Error



Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de) and create folder /apps/eaem-touchui-image-required

2) Create node /apps/eaem-touchui-image-required/clientlib of type cq:ClientLibraryFolder and add a String property categories with value cq.authoring.dialog and dependencies to underscore

3) Create file (nt:file) /apps/eaem-touchui-image-required/clientlib/js.txt and add

                       image-required.js

4) Create file (nt:file) /apps/eaem-touchui-image-required/clientlib/image-required.js and add the following code

(function ($, $document, gAuthor) {
    var EAEM_IMAGE_REQ_FIELD_ID_PREFIX = "eaem-img-required-",
        FILE_UPLOAD = ".coral-FileUpload",
        FILE_UPLOAD_CLEAR = ".cq-FileUpload-clear",
        DATA_ATTR_FILE_UPLOAD = "fileUpload",
        FILE_UPLOAD_SEL = ".coral-FileUpload-input",
        FILE_NAME = "./fileName",
        COMPONENT = "foundation/components/image",
        FIELD_ERROR_EL = $("<span class='coral-Form-fielderror coral-Icon coral-Icon--alert " +
                            "coral-Icon--sizeS' data-init='quicktip' data-quicktip-type='error'>" +
                        "</span>");
    if(!gAuthor){
        return;
    }

    $document.on('dialog-ready', checkFileRequired);

    function checkFileRequired(){
        var $fileUpload = $(FILE_UPLOAD),
            $fileName = $("[name='" + FILE_NAME + "']"),
            fileReqId = EAEM_IMAGE_REQ_FIELD_ID_PREFIX + getStringAfterLastSlash(FILE_NAME),
            editable = gAuthor.DialogFrame.currentDialog.editable;

        //if not an image component dialog, return
        if((editable.type !== COMPONENT) || _.isEmpty($fileName)){
            return;
        }

        //fileName field is hidden input, for the validator to work, add a invisible text field
        //holding the file name
        $fileUpload.append("<input type=text style='display:none' id='" + fileReqId + "'/>");

        var cuiFileUpload = $fileUpload.data(DATA_ATTR_FILE_UPLOAD),
            $fileReqInvisibleField = $("#" + fileReqId);

        addValidatorIfRequiredSet(editable, cuiFileUpload, $fileReqInvisibleField);
    }

    function addValidatorIfRequiredSet(editable, cuiFileUpload, $fileReqInvisibleField){
        var $fileUploadInput = cuiFileUpload.$element.find(FILE_UPLOAD_SEL);

        if ($fileUploadInput.attr("aria-required") !== "true") {
            return;
        }

        //user can either drop or upload an image; with required set to true
        //validator with selector: ".coral-FileUpload-input"
        //in /libs/granite/ui/components/foundation/clientlibs/foundation.js
        //always checks if there is a file queued for upload, so workaround it by removing
        //the required attribute on file upload input
        $fileUploadInput.removeAttr( "aria-required" );

        cuiFileUpload.$element.find(FILE_UPLOAD_CLEAR).on("click tap", function (e) {
            performRequiredCheck($fileReqInvisibleField, '');
        });

        cuiFileUpload.$element.on("fileuploadsuccess", function (event) {
            performRequiredCheck($fileReqInvisibleField, event.item.file.name);
        });

        cuiFileUpload.$element.on("assetselected", function (event) {
            performRequiredCheck($fileReqInvisibleField, event.path);
        });

        addValidator($fileReqInvisibleField);

        initRequiredField($fileReqInvisibleField, editable.path);
    }

    function initRequiredField($fileReqInvisibleField, path){
        var fileName = getStringAfterLastSlash(FILE_NAME);

        $.ajax(path + ".json").done(function(data){
            var value = data[fileName];

            if(_.isEmpty(value)){
                value = data["fileReference"];

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

                value = getStringAfterLastSlash(value);
            }

            $fileReqInvisibleField.val(value);
        })
    }

    function performRequiredCheck($fileReqInvisibleField, value){
        $fileReqInvisibleField.val(value);
        $fileReqInvisibleField.checkValidity();
        $fileReqInvisibleField.updateErrorUI();
    }

    function addValidator($fileReqInvisibleField){
        $.validator.register({
            selector: "#" + $fileReqInvisibleField.attr("id"),

            validate: validate ,

            show: show ,

            clear: clear
        });

        function validate($fileReqInvisibleField) {
            if (_.isEmpty($fileReqInvisibleField.val())) {
                return "Drop or upload an image";
            }

            return null;
        }

        function show($fileReqInvisibleField, message) {
            var $fileUploadField = $fileReqInvisibleField.closest(FILE_UPLOAD),
                arrow = $fileUploadField.closest("form").hasClass("coral-Form--vertical") ? "right" : "top",
                $error = $fileUploadField.nextAll(".coral-Form-fielderror");

            if (!_.isEmpty($error)) {
                return;
            }

            FIELD_ERROR_EL.clone()
                .attr("data-quicktip-arrow", arrow)
                .attr("data-quicktip-content", message)
                .insertAfter($fileUploadField);
        }

        function clear($fileReqInvisibleField) {
            var $fileUploadField = $fileReqInvisibleField.closest(FILE_UPLOAD);
            $fileUploadField.nextAll(".coral-Form-fielderror").remove();
        }
    }

    function getStringAfterLastSlash(str){
        if(!str || (str.indexOf("/") == -1)){
            return "";
        }

        return str.substr(str.lastIndexOf("/") + 1);
    }
}(jQuery, jQuery(document), Granite.author));

1 comment:

  1. Hi Sreekanth ,

    I was trying this in my component. It was successfully implemented and the validations are implementing correctly without any fail.

    But when i am dragging and dropping the image component on the same page . These validations are implemented in the image component also.
    I have implemented validations in my custom component only. Not in the image component.

    if((editable.type !== COMPONENT) || _.isEmpty($fileName)){
    return;
    }

    above piece of code is also not working:
    I have given COMPONENT="apps/myproject/components/mycustomcomponent"

    Please give some pointers on this.

    ReplyDelete