Search code examples
jqueryjqgridfree-jqgrid

jqGrid three level hierarchy subgrid Cell validation


I have a three level grid system, Product -> category -> item, where i expand the product row to see the subgrid category and on expanding a category row i get the item grid rows with inline editing of the cells. Now the user will be required to enter information in the item grid. i have cell validation once the user enters edit mode but have the option to not edit that row at all after adding it. Now the challenge is i need to validate the entire grid structure in this manner. 1) we will have a predefined number of products (products = 10) 2) predefine number of category pre product (5 category / product) 3) any number of items with cells non empty cells.

with a button "validate" i need to iterate through the entore grid system and 1st confirm the number of product 2nd confirm the number of categories/ product 3rd confirm no empty cells in the items grid for each of the product, category data. Hoping someone would help me on this. below is my grid syatem

        productGrid.jqGrid({
            url         : 'getList.php?ID=' + ID,
            editurl     : 'clientArray',
            mtype       : "GET",
            datatype    : "json",
            page        : 1,
            regional    : lang,
            colNames    : ['ID','product'],
            colModel    : [
                            { name: 'ID', width: 25, hidden: true },
                            { name: 'productID', key: true, editable: true, width: 20 },
                          ],
            loadonce    : true,
            autowidth   : true,
            //width: 525,
            height      : 500,
            rowNum      : 20,
            subGrid     : true, // set the subGrid property to true to show expand buttons for each row
            subGridRowExpanded  : showChildGrid, // javascript function that will take care of showing the child grid
            subGridOptions      : {
                        expandOnLoad: false, // expand all rows on load
                        plusicon: "fa fa-plus-circle",
                        minusicon: "fa fa-minus-circle",
                        openicon: "ui-icon-arrowreturn-1-e"
            },
            subGridBeforeExpand: function(divid, rowid) {
            var expanded = jQuery("td.sgexpanded", "#progGrid")[0];
                if(expanded) {
                    setTimeout(function(){
                        $(expanded).trigger("click");
                    }, 100);
                }
            },
            shrinkToFit: true,
            //altRows:true,
            //altclass:'myAltRowClass',
            sortorder: "asc",
            hidegrid:false,
            gridview: true,
            pgbuttons: false,     // disable page control like next, back button
            pgtext: null,
            viewrecords: true,

            pager: progExerGridPager
        }).navGrid(progExerGridPager, {edit: false, add: false, del: false, refresh: true, view: false, search:false})
          .inlineNav(progExerGridPager,
                                    {edit: true, add: true, del: true, cancel: true, refresh : true, editParams: {keys: true,}, addParams: {keys: true}
        });

        // the event handler on expanding parent row receives two parameters
        // the ID of the grid tow  and the primary key of the row  subgrid_id
        function showChildGrid(parentRowID, parentRowKey) {

            var childGridID = parentRowID + "_t";
            var childGridPagerID = parentRowKey + "_pager";

            // send the parent row primary key to the server so that we know which grid to show
            var childGridURL = 'getList.php?programID=' + programID +'&productID=' + parentRowKey;

            // add a table and pager HTML elements to the parent grid row - we will render the child grid here
            $('#' + parentRowID).append('<table id=' + childGridID + '></table><div id=' + childGridPagerID + ' class=scroll></div>');

            $("#" + childGridID).jqGrid({
                url: childGridURL,
                editurl: 'clientArray',
                mtype: "GET",
                datatype: "json",
                page: 1,
                regional: lang,
                caption :   "Category " + parentRowKey + " of Product",
                colNames:   ['categ_id', 'category'],
                colModel:   [
                            { name: 'categ_id',  width: 75, hidden: true },
                            { name: 'categoryID', key: true, width: 100, editable:true, editrules : { required: true, integer:true, minValue:1, maxValue:7}, },
                ],
                loadonce    : true,
                autowidth   :   true,
                //width     : 500,
                height: '100%',
                subGrid: true, // set the subGrid property to true to show expand buttons for each row
                subGridRowExpanded: showThirdLevelChildGrid, // javascript function that will take care of showing the child grid
                subGridOptions      : {
                        expandOnLoad: false, // expand all rows on load
                        plusicon: "fa fa-plus-circle",
                        minusicon: "fa fa-minus-circle",
                        openicon: "ui-icon-arrowreturn-1-e"
                },
                subGridBeforeExpand: function(divid, rowid) {
                // #grid is the id of the grid
                var expanded = jQuery("td.sgexpanded", "#" + childGridID )[0];
                    if(expanded) {
                        setTimeout(function(){
                            $(expanded).trigger("click");
                        }, 100);
                    }
                },
                shrinkToFit : true,
//              altRows     : true,
//              altclass    : 'myAltRowClass',
                sortorder   : "asc",
                hidegrid    : true,
                gridview    : true,
                pgbuttons   : false,     // disable page control like next, back button
                pgtext      : null,
                viewrecords : true,
                pager: '#' + childGridPagerID
            }).navGrid('#' + childGridPagerID, {edit: false, add: false, del: false, refresh: true, view: false, search:false})
              .inlineNav('#' + childGridPagerID,
                                        {edit: true, add: true, del: true, cancel: true, refresh : true, editParams: {keys: true,}, addParams: {keys: true}
            });
        }

        // the event handler on expanding parent row receives two parameters
        // the ID of the grid tow  and the primary key of the row

        // custom mask definition to allo X in the tempo
        //$.mask.definitions['x']='[x-9]';

        function showThirdLevelChildGrid(parentRowID, parentRowKey) {
            var childGridID = parentRowID + "_table";
            var childGridPagerID = parentRowID + "_pager";
            var rowID = parentRowID.split('_');
            var productID = rowID[1];

            // send the parent row primary key to the server so that we know which grid to show
            var childGridURL = 'getList.php?programID=' + programID + '&productID=' + productID + '&categoryID=' + parentRowKey;

            // add a table and pager HTML elements to the parent grid row - we will render the child grid here
            $('#' + parentRowID).append('<table id=' + childGridID + '></table><div id=' + childGridPagerID + ' class=scroll></div>');

            $("#" + childGridID).jqGrid({
                url: childGridURL,
                editurl: 'clientArray',
                mtype: "GET",
                datatype: "json",
                caption :   "Item " + parentRowKey + " Product/Category",
                regional: lang,
                colNames:   ['ItemID', 'Name', 'Quantity', 'Range', 'Rate', 'Inventory', 'Type', 'Note'],
                colModel: [
                    {  name: 'ID', key: true, width: 75, hidden: true },
                    {  name: 'Name', width: 200, editable: false, editrules : { required: true},
                            cellattr: function (rowId, tv, rawObject, cm, rdata) {
                                return 'style="white-space: normal;'
                            },
                    },
                    {  name: 'Quantity', width: 70, align: 'center', editable: true, editrules : { required: true, integer:true}},
                    {  name: 'Range', width: 80, align: 'center', editable: true, edittype:'text', editrules : { required: true},
                            editoptions: {
                                dataInit: function (elem) {
                                    $(elem).mask("99~99",{
                                        placeholder :" ",
                                        completed   :function(){
                                            // validate the ranges
                                            var repRange = this.val().split("~"),
                                                fromRange = repRange[0],
                                                toRange = repRange[1];

                                            if (fromRange > toRange) {
                                                alert("the lower range cannot be higher than the High range");
                                                // clear the box
                                                this.val("");
                                            }
                                        }
                                    });
                                }
                            }
                    },
                    {  name: 'Rate', width: 100, align: 'center', editable: true, edittype:'text', editrules : { required: true},
                            editoptions: {
                                dataInit: function (elem) {
                                    $(elem).mask("9-9",{
                                        placeholder :" ",
                                    });
                                }
                            }
                    },
                    {  name: 'Inventory', width: 80, align: 'center', editable: true, editrules : { required: true, integer:true}},
                    {  name: 'Type', width: 100, align: 'center', editable: true, editrules : { required: true}, edittype: "select", editoptions : {value: exerciseType}},
                    {  name: 'Note', width: 100, editable: true, edittype:"textarea", editoptions:{rows:"5",cols:"45"}, hidden:true, editrules:{edithidden:true}},
                    //}
                ],
                recreateForm: true,
                loadonce    : true,
                //onSelectRow   : editRow,
                autowidth   : true,
                //width     : 'auto',
                height      : '100%',
                shrinkToFit : true,
//              altRows     : true,
//              altclass    : 'myAltRowClass',
                sortorder   : "asc",
                hidegrid    : false,
                gridview    : true,
                pgbuttons   : false,     // disable page control like next, back button
                pgtext      : null,
                rownumbers  : true, // show row numbers
                rownumWidth : 20, // the width of the row numbers columns
                viewrecords : true,
                pager       : "#" + childGridPagerID
            }).navGrid('#' + childGridPagerID, {edit: true, add: false, del: false, refresh: true, view: false, search:false})
              .inlineNav('#' + childGridPagerID,
                                        {edit: true, add: false, del: true, cancel: true, refresh : true, editParams: {keys: true,}, addParams: {keys: true}
            });

Solution

  • So I went for server side validation and displayed the results outside of the grid. got more control and easier to implement, specially on the cell validation part.