AEM 61 - Sample Granite Widget In Touch UI extending Multifield to Limit Items

Goal


Create Touch UI Limit Multifield widget extending Granite Multifield widget, for limiting the number of items added in a multifield

Unlike Classic UI xtypes, widgets in Granite framework work with server-side rendering principles (html prepared on the server and executed on client). This sample Touch UI Granite widget is analogous to Classic UI xtype with following inheritance

/apps/touchui-limit-multifield ->  /libs/granite/ui/components/foundation/form/multifield -> /libs/granite/ui/components/foundation/form/field

Dialog of foundation page component (/libs/foundation/components/page/cq:dialog/content/items/tabs/items/basic/items/column/items/vanityurl/items/vanitypath) modified for demonstration only (on Geometrixx pages), ideally the foundation components should never be altered...

For Classic UI check this post

Demo | Package Install


Configure fieldLimit, set sling:resourceType to /apps/touchui-limit-multifield




Page Properties Dialog Validation Error


Page Properties Dialog Full Screen Validation Error


Solution


1) Login to CRXDE Lite, create nt:folder /apps/touchui-limit-multifield

2) Create nt:file /apps/touchui-limit-multifield/touchui-limit-multifield.jsp, add the following code. JS can be separated out into a clientlib

<%@ page import="com.adobe.granite.ui.components.Config" %>

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

<%--include ootb multifield--%>
<sling:include resourceType="/libs/granite/ui/components/foundation/form/multifield"/>

<%
    Config mCfg = cmp.getConfig();

    Resource mField = mCfg.getChild("field");

    ValueMap mVM = mField.getParent().adaptTo(ValueMap.class);

    String mFieldLimit = mVM.get("fieldLimit", "");

    if(mFieldLimit.equals("")){
        return;
    }

    String countValidatorId = "multifield-validator-" + System.currentTimeMillis(); //or some random number
%>

<%--
coral validation framework ignores hidden and contenteditable fields, so add an invisible text field
the text field is just for registering a validator
--%>
<input type=text style='display:none' id="<%=countValidatorId%>"/>

<script>
    (function($){
        var fieldErrorEl = $("<span class='coral-Form-fielderror coral-Icon coral-Icon--alert coral-Icon--sizeS' " +
                                "data-init='quicktip' data-quicktip-type='error' />");

        var $countValidatorField = $("#<%=countValidatorId%>"),
            $multifield = $countValidatorField.prev().find(".coral-Multifield"),
            fieldLimit = parseInt($multifield.data("fieldlimit")),
            count = $multifield.find(".coral-Multifield-input").length;

        //add validator on the multifield
        $.validator.register({
            selector: $countValidatorField,
            validate: validate,
            show: show,
            clear: clear
        });

        $multifield.on("click", ".js-coral-Multifield-add", function (e) {
            ++count;
            adjustMultifieldUI();
        });

        $multifield.on("click", ".js-coral-Multifield-remove", function (e) {
            --count;
            adjustMultifieldUI();
        });

        function adjustMultifieldUI(){
            $countValidatorField.checkValidity();
            $countValidatorField.updateErrorUI();

            /*var $addButton = $multifield.find(".js-coral-Multifield-add");

            if(count >= fieldLimit){
                $addButton.attr('disabled','disabled');
            }else{
                $addButton.removeAttr('disabled');
            }*/
        }

        function validate(){
            if(count <= fieldLimit){
                return null;
            }

            return "Limit set to " + fieldLimit;
        }

        function show($el, message){
            this.clear($countValidatorField);

            var arrow = $multifield.closest("form").hasClass("coral-Form--vertical") ? "right" : "top";

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

        function clear(){
            $multifield.nextAll(".coral-Form-fielderror").tooltip("hide").remove();
        }
    })(jQuery);
</script>

3) #6 for extending ootb mulitifield /libs/granite/ui/components/foundation/form/multifield using sling:include

4) #41 for registering a validator on the multifield, #48, #53 to trigger validator when user adds/removes items

5) To use the Limit Multifield in a TouchUI Dialog, set the following properties on node

                   sling:resourceType         /apps/touchui-limit-multifield
                   fieldLimit                 Integer eg. 3





2 comments:

  1. I cannot see the error message when I try to add more fields that specified in the fieldLimit.
    Please suggest a solution.

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete