0
votes

In AEM touch UI dialog,I am having a multi field having a text field and pathfield.

Now i want to make title as required field in my custom multifield.But unable to do so.

My xml for composite multifield tab is:

 <advanced
            jcr:primaryType="nt:unstructured"
            jcr:title="Advanced"
            sling:resourceType="granite/ui/components/foundation/section">
            <layout
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
            <items jcr:primaryType="nt:unstructured">
                <column
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/foundation/container"
                    class="column-full-width">
                    <items jcr:primaryType="nt:unstructured">
                        <fieldset
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/foundation/form/fieldset">
                            <layout
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
                            <items jcr:primaryType="nt:unstructured">
                                <column
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <items
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/foundation/form/multifield"
                                            class="full-width"
                                            fieldDescription="Click 'Add field' button to add a new field."
                                            fieldLabel="Resources">
                                            <field
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/foundation/form/fieldset"
                                                eaem-nested=""
                                                name="./items">
                                                <layout
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
                                                <items jcr:primaryType="nt:unstructured">
                                                    <column
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/foundation/container">
                                                        <items jcr:primaryType="nt:unstructured">
                                                            <title
                                                                jcr:primaryType="nt:unstructured"
                                                                fieldDescription="Pdf/Video Title is mandatory."
                                                                sling:resourceType="granite/ui/components/foundation/form/textfield"
                                                                fieldLabel="Title: Pdf/video"
                                                                name="./title"/>
                                                            <path
                                                                jcr:primaryType="nt:unstructured"
                                                                rootPath="/content/dam"
                                                                sling:resourceType="granite/ui/components/foundation/form/pathbrowser"
                                                                fieldLabel="Path: Pdf/video"
                                                                name="./path"/>
                                                        </items>
                                                    </column>
                                                </items>
                                            </field>
                                        </items>
                                    </items>
                                </column>
                            </items>
                        </fieldset>
                    </items>
                </column>
            </items>
        </advanced>

And the JS code for the same is :

(function () {
var DATA_EAEM_NESTED = "data-eaem-nested";
var CFFW = ".coral-Form-fieldwrapper";

//reads multifield data from server, creates the nested composite multifields and fills them
function addDataInFields() {
    $(document).on("dialog-ready", function() {

        var $fieldSets = $("[" + DATA_EAEM_NESTED + "][class='coral-Form-fieldset']");
        if(_.isEmpty($fieldSets)){
            return;
        }

        var mNames = [];

        $fieldSets.each(function (i, fieldSet) {
            mNames.push($(fieldSet).data("name"));
        });

        mNames = _.uniq(mNames);

        var actionUrl = $fieldSets.closest("form.foundation-form").attr("action") + ".json";

        $.ajax(actionUrl).done(postProcess);

        function postProcess(data){
            _.each(mNames, function(mName){
                buildMultiField(data, mName);
            });
        }

        //creates & fills the nested multifield with data
        function fillNestedFields($multifield, valueArr){
            _.each(valueArr, function(record, index){
                $multifield.find(".js-coral-Multifield-add").click();

                //a setTimeout may be needed
                _.each(record, function(value, key){
                    var $field = $($multifield.find("[name='./" + key + "']")[index]);
                    $field.val(value);
                })
            })
        }

        function buildMultiField(data, mName){
            if(_.isEmpty(mName)){
                return;
            }

            $fieldSets = $("[data-name='" + mName + "']");

            //strip ./
            mName = mName.substring(2);

            var mValues = data[mName], $field, name;

            if(_.isString(mValues)){
                mValues = [ JSON.parse(mValues) ];
            }

            _.each(mValues, function (record, i) {
                if (!record) {
                    return;
                }

                if(_.isString(record)){
                    record = JSON.parse(record);
                }

                _.each(record, function(rValue, rKey){
                    $field = $($fieldSets[i]).find("[name='./" + rKey + "']");

                    if(_.isArray(rValue) && !_.isEmpty(rValue)){
                        fillNestedFields( $($fieldSets[i]).find("[data-init='multifield']"), rValue);
                    }else{
                            var select = $field.closest(".coral-Select").data("select");
                            if(select){
                                select.setValue(rValue);
                            }
                            else{
                        $field.val(rValue);
                        }
                    }
                });
            });
        }
    });
}

function fillValue($field, record){
    var name = $field.attr("name");

    if (!name) {
        return;
    }

    //strip ./
    if (name.indexOf("./") == 0) {
        name = name.substring(2);
    }

    record[name] = $field.val();

    //remove the field, so that individual values are not POSTed
    $field.remove();
}

//for getting the nested multifield data as js objects
function getRecordFromMultiField($multifield){
    var $fieldSets = $multifield.find("[class='coral-Form-fieldset']");

    var records = [], record, $fields, name;

    $fieldSets.each(function (i, fieldSet) {
        $fields = $(fieldSet).find("[name]");

        record = {};

        $fields.each(function (j, field) {
            fillValue($(field), record);
        });

        if(!$.isEmptyObject(record)){
            records.push(record)
        }
    });

    return records;
}

//collect data from widgets in multifield and POST them to CRX as JSON
function collectDataFromFields(){
    $(document).on("click", ".cq-dialog-submit", function () {
        var $form = $(this).closest("form.foundation-form");
        var $fieldSets = $("[" + DATA_EAEM_NESTED + "][class='coral-Form-fieldset']");
        var record, $fields, $field, name, $nestedMultiField;

        $fieldSets.each(function (i, fieldSet) {
            $fields = $(fieldSet).children().children(CFFW);

            record = {};

            $fields.each(function (j, field) {
                $field = $(field);

                //may be a nested multifield
                $nestedMultiField = $field.find("[data-init='multifield']");

                if($nestedMultiField.length == 0){
                    fillValue($field.find("[name]"), record);
                }else{
                    name = $nestedMultiField.find("[class='coral-Form-fieldset']").data("name");

                    if(!name){
                        return;
                    }

                    //strip ./
                    name = name.substring(2);

                    record[name] = getRecordFromMultiField($nestedMultiField);
                }
            });

            if ($.isEmptyObject(record)) {
                return;
            }

            //add the record JSON in a hidden field as string
            $('<input />').attr('type', 'hidden')
                .attr('name', $(fieldSet).data("name"))
                .attr('value', JSON.stringify(record))
                .appendTo($form);
        });
    });
}

$(document).ready(function () {
    addDataInFields();
    collectDataFromFields();
});

//extend otb multifield for adjusting event propagation when there are nested multifields
//for working around the nested multifield add and reorder
CUI.CustomMultifield = new Class({
    toString: "Multifield",
    extend: CUI.Multifield,

    construct: function (options) {
        this.script = this.$element.find(".js-coral-Multifield-input-template:last");
    },

    _addListeners: function () {
        this.superClass._addListeners.call(this);

        //otb coral event handler is added on selector .js-coral-Multifield-add
        //any nested multifield add click events are propagated to the parent multifield
        //to prevent adding a new composite field in both nested multifield and parent multifield
        //when user clicks on add of nested multifield, stop the event propagation to parent multifield
        this.$element.on("click", ".js-coral-Multifield-add", function (e) {
            e.stopPropagation();
        });

        this.$element.on("drop", function (e) {
            e.stopPropagation();
        });
    }
});

CUI.Widget.registry.register("multifield", CUI.CustomMultifield);})();

When i am making textfield as required:true it doesn't work for me.

1
will be better if you post any code snippet what you have tried and which causes failure of your custom multifield.VAr
your component JS looks similar like this post except some fields in dialog. by the by how are you testing the mandatory field for the textfield after adding the required:boolean:true. ?. The required field will be enabled after a character type and delete it. Note that it is not on enabled on your dialog load.VAr
Yes Var ,I am doing the same thing.But my dialog get closed either i don't enter the value in it. And yes i copied the js from here only.Shivani Garg

1 Answers

-1
votes

This works fine for me

Dialog Node:

<content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
    <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
    <items jcr:primaryType="nt:unstructured">
        <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
            <items jcr:primaryType="nt:unstructured">
                <fieldset jcr:primaryType="nt:unstructured" jcr:title="Test Mandatory TextField" sling:resourceType="granite/ui/components/foundation/form/fieldset">
                    <layout jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
                    <items jcr:primaryType="nt:unstructured">
                        <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
                            <items jcr:primaryType="nt:unstructured">
                                <states jcr:primaryType="nt:unstructured" class="full-width" fieldDescription="Click '+' to add a new page" fieldLabel="Resources" sling:resourceType="granite/ui/components/foundation/form/multifield">
                                    <field jcr:primaryType="nt:unstructured" eaem-nested="" name="./states" sling:resourceType="granite/ui/components/foundation/form/fieldset">
                                        <layout jcr:primaryType="nt:unstructured" method="absolute" sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
                                        <items jcr:primaryType="nt:unstructured">
                                            <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/foundation/container">
                                                <items jcr:primaryType="nt:unstructured">
                                                    <title jcr:primaryType="nt:unstructured" fieldDescription="Pdf/Video Title is mandatory." fieldLabel="Title: Pdf/video" name="./title" required="true" sling:resourceType="granite/ui/components/foundation/form/textfield"/>
                                                    <path jcr:primaryType="nt:unstructured" fieldDescription="Select Path" fieldLabel="Path for Pdf/video" name="./path" rootPath="/content" sling:resourceType="granite/ui/components/foundation/form/pathbrowser"/>
                                                </items>
                                            </column>
                                        </items>
                                    </field>
                                </states>
                            </items>
                        </column>
                    </items>
                </fieldset>
            </items>
        </column>
    </items>
</content>

JS Code

(function () {
    var DATA_EAEM_NESTED = "data-eaem-nested";
    var CFFW = ".coral-Form-fieldwrapper";

    //reads multifield data from server, creates the nested composite multifields and fills them
    var addDataInFields = function () {
        $(document).on("dialog-ready", function() {
            var mName = $("[" + DATA_EAEM_NESTED + "]").data("name");

            if(!mName){
                return;
            }

            //strip ./
            mName = mName.substring(2);

            var $fieldSets = $("[" + DATA_EAEM_NESTED + "][class='coral-Form-fieldset']"),
                $form = $fieldSets.closest("form.foundation-form");

            var actionUrl = $form.attr("action") + ".json";

            var postProcess = function(data){
                if(!data || !data[mName]){
                    return;
                }

                var mValues = data[mName], $field, name;

                if(_.isString(mValues)){
                    mValues = [ JSON.parse(mValues) ];
                }

                _.each(mValues, function (record, i) {
                    if (!record) {
                        return;
                    }

                    if(_.isString(record)){
                        record = JSON.parse(record);
                    }

                    _.each(record, function(rValue, rKey){
                        $field = $($fieldSets[i]).find("[name='./" + rKey + "']");

                        if(_.isArray(rValue) && !_.isEmpty(rValue)){
                            fillNestedFields( $($fieldSets[i]).find("[data-init='multifield']"), rValue);
                        }else{
                            $field.val(rValue);
                        }
                    });
                });
            };

            //creates & fills the nested multifield with data
            var fillNestedFields = function($multifield, valueArr){
                _.each(valueArr, function(record, index){
                    $multifield.find(".js-coral-Multifield-add").click();

                    //a setTimeout may be needed
                    _.each(record, function(value, key){
                        var $field = $($multifield.find("[name='./" + key + "']")[index]);
                        $field.val(value);
                    })
                })
            };

            $.ajax(actionUrl).done(postProcess);
        });
    };

    var fillValue = function($field, record){
        var name = $field.attr("name");

        if (!name) {
            return;
        }

        //strip ./
        if (name.indexOf("./") == 0) {
            name = name.substring(2);
        }

        record[name] = $field.val();

        //remove the field, so that individual values are not POSTed
        $field.remove();
    };

    //for getting the nested multifield data as js objects
    var getRecordFromMultiField = function($multifield){
        var $fieldSets = $multifield.find("[class='coral-Form-fieldset']");

        var records = [], record, $fields, name;

        $fieldSets.each(function (i, fieldSet) {
            $fields = $(fieldSet).find("[name]");

            record = {};

            $fields.each(function (j, field) {
                fillValue($(field), record);
            });

            if(!$.isEmptyObject(record)){
                records.push(record)
            }
        });

        return records;
    };

    //collect data from widgets in multifield and POST them to CRX as JSON
    var collectDataFromFields = function(){
        $(document).on("click", ".cq-dialog-submit", function () {
            var $form = $(this).closest("form.foundation-form");

            var mName = $("[" + DATA_EAEM_NESTED + "]").data("name");
            var $fieldSets = $("[" + DATA_EAEM_NESTED + "][class='coral-Form-fieldset']");

            var record, $fields, $field, name, $nestedMultiField;

            $fieldSets.each(function (i, fieldSet) {
                $fields = $(fieldSet).children().children(CFFW);

                record = {};

                $fields.each(function (j, field) {
                    $field = $(field);

                    //may be a nested multifield
                    $nestedMultiField = $field.find("[data-init='multifield']");

                    if($nestedMultiField.length == 0){
                        fillValue($field.find("[name]"), record);
                    }else{
                        name = $nestedMultiField.find("[class='coral-Form-fieldset']").data("name");

                        if(!name){
                            return;
                        }

                        //strip ./
                        name = name.substring(2);

                        record[name] = getRecordFromMultiField($nestedMultiField);
                    }
                });

                if ($.isEmptyObject(record)) {
                    return;
                }

                //add the record JSON in a hidden field as string
                $('<input />').attr('type', 'hidden')
                    .attr('name', mName)
                    .attr('value', JSON.stringify(record))
                    .appendTo($form);
            });
        });
    };

    $(document).ready(function () {
        addDataInFields();
        collectDataFromFields();
    });

    //extend otb multifield for adjusting event propagation when there are nested multifields
    //for working around the nested multifield add and reorder
    CUI.Multifield = new Class({
        toString: "Multifield",
        extend: CUI.Multifield,

        construct: function (options) {
            this.script = this.$element.find(".js-coral-Multifield-input-template:last");
        },

        _addListeners: function () {
            this.superClass._addListeners.call(this);

            //otb coral event handler is added on selector .js-coral-Multifield-add
            //any nested multifield add click events are propagated to the parent multifield
            //to prevent adding a new composite field in both nested multifield and parent multifield
            //when user clicks on add of nested multifield, stop the event propagation to parent multifield
            this.$element.on("click", ".js-coral-Multifield-add", function (e) {
                e.stopPropagation();
            });

            this.$element.on("drop", function (e) {
                e.stopPropagation();
            });
        }
    });
CUI.Widget.registry.register("multifield", CUI.Multifield);
})();

textfield mandatory dialogdata JCR Content