1

I'm working on the jqgrid which gets bound dynamically. I have got the required output. But i wrote a big code which affects my performance and its not readable.

I need someone who can look into this and optimize my code simple.

Thanks in advance.

I have reproduced in my working code here

 $.each($.parseJSON(columnsData).Table1, function () {
            // debugger;
            //Push the column name.
            colHeader.push(this.Name);

            //Check the datatype of the column.
            switch (this.Datatype) {

                case 'number':
                    if (this.DefaultValue != null && this.DefaultValue != "") {
                        //  debugger;
                        colname.push({
                            name: this.Name, index: this.Name, width: 100, align: 'left', formatter: 'number', sortable: true, editable: false, sorttype: 'int', hidden: JSON.parse(this.IsHidden), editoptions: {
                                defaultValue: this.DefaultValue
                            }, editrules: { required: JSON.parse(this.IsRequired) }

                        });
                    }
                    else {
                        colname.push({
                            name: this.Name, index: this.Name, width: 100, align: 'left', formatter: 'number', sortable: true, editable: false, sorttype: 'int', hidden: JSON.parse(this.IsHidden), editrules: { required: JSON.parse(this.IsRequired) }
                        });
                    }
                    lastFieldName = this.Name.toString(); //Store the fieldName.
                    break;
                case 'DateTime':
                    if (this.DefaultValue != null && this.DefaultValue != "") {
                        //If datetime then enable datepicker in the filter and edit form.
                        colname.push({
                            name: this.Name, search: true, index: this.Name, width: 100, stype: "text", editable: true, hidden: JSON.parse(this.IsHidden), searchoptions: {

                                dataInit: function (el) {

                                    $(el).datepicker({
                                        dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true, onSelect: function (dateText, inst) {
                                            setTimeout(function () {
                                                $('#TransactionsGrid')[0].triggerToolbar();
                                            }, 50);
                                        }
                                    });

                                }
                            }, editoptions: {

                                dataInit: function (el) {

                                    $(el).datepicker({
                                        dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true
                                    });

                                }, defaultValue: this.DefaultValue, readonly: 'readonly'
                            }, editrules: { required: JSON.parse(this.IsRequired) }
                        });
                    }
                    else {
                        colname.push({
                            name: this.Name, search: true, index: this.Name, width: 100, stype: "text", editable: true, hidden: JSON.parse(this.IsHidden), searchoptions: {

                                dataInit: function (el) {

                                    $(el).datepicker({
                                        dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true, onSelect: function (dateText, inst) {
                                            setTimeout(function () {
                                                $('#TransactionsGrid')[0].triggerToolbar();
                                            }, 50);
                                        }
                                    });

                                }
                            }, editoptions: {

                                dataInit: function (el) {

                                    $(el).datepicker({
                                        dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true
                                    });

                                }
                            }, editrules: { required: JSON.parse(this.IsRequired) }
                        });
                    }
                    lastFieldName = this.Name.toString();
                    break;
                case 'dropdown':
                    if (this.DefaultValue != null && this.DefaultValue != "") {
                        //   debugger;
                        if (this.ValueType == "F") {
                            colname.push({

                                name: this.Name, index: this.Name, width: 100, edittype: "select", editable: true, hidden: JSON.parse(this.IsHidden),
                                //formatter: imageFormatter, unformat: imageUnFormat,

                                /*(Set tooltip of the gridcell)
                                cellattr: function (rowId, val, rawObject, cm, rdata) {
                                if (rawObject[cm.name + "_Title"] == "") {
                                return 'title="' + rawObject[cm.name] + '"';
                                }
                                else
                                return 'title="' + val + ' (' + rawObject[cm.name + "_Title"] + ')"';
                                },*/

                                //IF dropdown then bind the values during edit form.
                                editoptions: { value: ':Select;' + this.ValueList.slice(0, -1), defaultValue: this.DefaultValue }, editrules: { required: JSON.parse(this.IsRequired) }, stype: 'select'
                                            , searchoptions: { value: ':All;' + this.ValueList.slice(0, -1) }, align: 'left', sortable: true

                            });
                        }
                        else {
                            colname.push({

                                name: this.Name, index: this.Name, width: 100, edittype: "select", label: this.ValueId, hidden: JSON.parse(this.IsHidden),


                                //IF dropdown then bind the values during edit form.
                                editoptions: { value: ':Select;' + this.ValueList.slice(0, -1), defaultValue: this.DefaultValue }, editrules: { required: JSON.parse(this.IsRequired) }, stype: 'select'
                                           , searchoptions: { value: ':All;' + this.ValueList.slice(0, -1) }, align: 'left', sortable: true

                            });
                        }
                    }
                    else {
                        if (this.ValueType == "F") {
                            colname.push({

                                name: this.Name, index: this.Name, width: 100, edittype: "select", editable: true, hidden: JSON.parse(this.IsHidden),

                                //IF dropdown then bind the values during edit form.
                                editoptions: { value: ':Select;' + this.ValueList.slice(0, -1) }, editrules: { required: JSON.parse(this.IsRequired) }, stype: 'select'
                                            , searchoptions: { value: ':All;' + this.ValueList.slice(0, -1) }, align: 'left', sortable: true

                            });
                        }
                        else {
                            colname.push({

                                name: this.Name, index: this.Name, width: 100, edittype: "select", label: this.ValueId, hidden: JSON.parse(this.IsHidden),


                                //IF dropdown then bind the values during edit form.
                                editoptions: { value: ':Select;' + this.ValueList.slice(0, -1) }, editrules: { required: JSON.parse(this.IsRequired) }, stype: 'select'
                                           , searchoptions: { value: ':All;' + this.ValueList.slice(0, -1) }, align: 'left', sortable: true

                            });
                        }
                    }
                    break;
                default:
                    if (this.DefaultValue != null && this.DefaultValue != "") {
                        colname.push({
                            name: this.Name, index: this.Name, width: 100, align: 'left', sortable: true, editable: true, hidden: JSON.parse(this.IsHidden), editrules: { required: JSON.parse(this.IsRequired) }
                        });
                    }
                    else {
                        colname.push({
                            name: this.Name, index: this.Name, width: 100, align: 'left', sortable: true, editable: true, hidden: JSON.parse(this.IsHidden), editrules: { required: JSON.parse(this.IsRequired) }
                        });
                    }
                    break;
            }


        });

jQuery("#TransactionsGrid").jqGrid({
    data: $.parseJSON(gridData).BuildTransactionsDataTable,
    datatype: "local",
    hoverrows: false,
    colNames: colHeader,
    colModel: colname,
    id: 'TransactionId',
    rowNum: 10,
    rownumbers: true,
    sortname: '_id',
    viewrecords: true,
    sortorder: 'desc',
    caption: "Transaction Details",
    height: '250px',
    gridview: true,
    ignoreCase: true

});

Since the code is too large to view, i have made the fiddle. Kindly look into that

Updated:

The cases i have to handle in my controller and when used the same in client(this.DataType) side the code will be a big one.

// Code:

case FieldStyleModel.FieldType.Date:
case FieldStyleModel.FieldType.DropDownCalendar:
case FieldStyleModel.FieldType.DateWithoutDropDown:
case FieldStyleModel.FieldType.DateWithSpin:
    drColumnDetails["Datatype"] = "date";
    break;
case FieldStyleModel.FieldType.DateTime:
case FieldStyleModel.FieldType.DateTimeWithoutDropDown:
case FieldStyleModel.FieldType.DateTimeWithSpin:
    drColumnDetails["Datatype"] = "datetime";
    break;
case FieldStyleModel.FieldType.DropDown:
case FieldStyleModel.FieldType.DropDownList:
case FieldStyleModel.FieldType.DropDownValidate:
    drColumnDetails["Datatype"] = "dropdown";
    break;
case FieldStyleModel.FieldType.URL:
    drColumnDetails["Datatype"] = "hyperlink";
    break;
case FieldStyleModel.FieldType.IntegerNonNegative:
case FieldStyleModel.FieldType.IntegerNonNegativeWithSpin:
case FieldStyleModel.FieldType.IntegerPositive:
case FieldStyleModel.FieldType.IntegerPositiveWithSpin:
    drColumnDetails["Datatype"] = "number";
    break;
case FieldStyleModel.FieldType.Integer:
case FieldStyleModel.FieldType.IntegerWithSpin:
    drColumnDetails["Datatype"] = "integer";
    break;
case FieldStyleModel.FieldType.Time:
case FieldStyleModel.FieldType.TimeWithSpin:
case FieldStyleModel.FieldType.TimeZone:
    drColumnDetails["Datatype"] = "Time";
    break;
case FieldStyleModel.FieldType.CheckBox:
    drColumnDetails["Datatype"] = "checkbox";
    break;
default:
    drColumnDetails["Datatype"] = "string";
    break;
Habeeb
  • 1,020
  • 16
  • 35

1 Answers1

1

Small common remarks:

  • the value of parameter height can be wither a number like height: 250 or string "auto" or "100%". The value '250px' is incorrect. My favorit value for height is "auto".
  • you should remove unknown id option of jqGrid (see id: 'TransactionId' in your code).
  • the value sortname: '_id' is suspected. Do you really have _id property in every items of the input data?
  • if the input data $.parseJSON(gridData).BuildTransactionsDataTable contains only the data should be interpreted as text and not as HTML fragments then I'd recommend you to use autoencode: true option of jqGrid,

If you load many thousand of rows of data in the grid then the trick described in the answer can improve performance of loading of data in the grid. You need just do two steps:

  1. Remove sortname and sortorder options of the grid. Sorting of large dataset can take time. No sortname (or sortname: "") means displaying unsorted data. It will improve the performace of initial loading of data.
  2. Remove data option of the grid and set it inside of onInitGrid callback instead:
$("#TransactionsGrid").jqGrid({
    datatype: "local",
    hoverrows: false,
    colNames: colHeader,
    colModel: colname,
    rowNum: 10,
    rownumbers: true,
    viewrecords: true,
    caption: "Transaction Details",
    height: "auto",
    gridview: true,
    autoencode: true,
    ignoreCase: true,
    onInitGrid: function () {
        // get reference to parameters
        var p = $(this).jqGrid("getGridParam");

        // set data parameter
        p.data = $.parseJSON(gridData).BuildTransactionsDataTable;
    }
});

The demo from the answer loads 90000 rows of data and the loading takes about 52-130 ms depend on the web browser which I use. It's a good time in my opinion. Without the trick (see the demo) the loading of data takes about 1600-11000 ms. If one add sorting of the data (see one more demo) then I get the time between 2100-29000 ms.

UPDATED: First of all you should remove from JavaScript code all unneeded things.

  • The index properties must be the same as the value of name properties. If you remove index properties jqGrid internally will create correct index values. So I strictly recommend all don't specify index properties in colModel.
  • I recommend you to move all common properties (or the most common properties) from colModel items in the cmTemplate. For example if you use width: 100 in all items of colModel you should remove the property and add jqGrid option cmTemplate: { width: 100 } instead placing the property width with the same value inside of every item of colModel.
  • I recommend you examine the value from Default column in the table with the properties of colModel in the documentation. You will find that placing of align: 'left', editable: false, sortable: true, stype: "text" and some other properties are unneeded. I recommend you remove the properties.
  • If you have some native unique id for the data which come from the backend I would recommend yot to use it as the rowid. There are two option: 1) you need to display the column to the user. In the case you need just add key: true property in colModel 2) you don't need to display the id to the user. In the case you don't need create any hidden column with the data. Instead of that you can just add localReader: { id: "TransactionId" } option to inform jqGrid where to get the rowids. The usage of native rowids will be especially practical for editing. The id parameter with rowid will be send by jqGrid to the server during editing. I recommend you to use prmNames: { id: "TransactionId" } additionally. In the case jqGrid with name the property with rowid as "TransactionId" instead of default name "id" during editing.
  • You fill colNames with the values of name property of colModel. You don't need do this. I recommend you don't specify colNames option at all in the case. In the case jqGrid will fill colNames internally with the values of label property of colModel or the value of name property if label not exist.
  • I recommend you to hide columns which empty (null, "", " " etc) values in all items of data. It makes the user easier to read the grid and improves the performance of the grid. Displaying of many columns is much more expensive for the web browser as displaying of many rows. So hiding unneeded columns can improve performance of the grid.
  • One more important important problem which I not yet fix in the demo is the following. You use wrong values of name property. Your current code contains columns having name: "Employee Name" or name: "Avg.Num Of Steps Occur". It's important to understand that name property will be used to build id attributes of some internal jqGrid elements and will be used in selectors. jQuery selectors should don't contains any meta-charackters (!"#$%&'()*+,./:;<=>?@[\]^``{|}~). Additionally id of HTML 4 for example can't contains spaces. See here. I strictly recommend you to use only letters ([A-Za-z]), digits ([0-9]), hyphens ("-") or underscores ("_") in the name. The first symbol should be a letter. If you don't follow the rule you can have many problems (problems in sorting, searching etc.). Probably you should set label: this.Name property and used some rules to build correct name value based on this.Name. You should include the property with original this.Name property during editing, so that the result of editing will be sent the same as before fixing of name property.

As the result I modified your code to the following: http://jsfiddle.net/z1ujyh02/6/. The most important part of the code I included below:

var columnsData = "...", gridData = "...";
var mydata = $.parseJSON(gridData).BuildTransactionsDataTable, existingProperties = {},
    numberTemplate = {formatter: 'number', sorttype: 'int'},
    dateTemplate = {
        editable: true,
        searchoptions: {
            dataInit: function (el) {
                var self = this;
                $(el).datepicker({
                    dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true,
                    onSelect: function (dateText, inst) {
                        setTimeout(function () {
                            self.triggerToolbar();
                        }, 50);
                    }
                });
            }
        },
        editoptions: {
            dataInit: function (el) {
                $(el).datepicker({
                    dateFormat: 'm/d/yy', maxDate: 0, changeMonth: true, changeYear: true
                });
            },
            readonly: 'readonly'
        }
    }
    dropdownTemplate = {
        edittype: "select",
        editable: true,
        stype: "select"
    };

$.each(mydata, function () {
    var p;
    for (p in this) {
        if (this.hasOwnProperty(p) && this[p] !== null && (typeof this[p] === "string" && $.trim(this[p]) !== "")) {
            existingProperties[p] = true;
        }
    }
});

var colname = [{ name: "TransactionId", sorttype: "int", key: true }];
//Loop into the column values collection and push into the array.
$.each($.parseJSON(columnsData).Table1, function () {
    //Check the datatype of the column.
    var cm = {
            name: this.Name,
            hidden: JSON.parse(this.IsHidden) || !existingProperties.hasOwnProperty(this.Name),
            editoptions: this.DefaultValue != null && this.DefaultValue != "" ? { defaultValue: this.DefaultValue } : {},
            editrules: { required: JSON.parse(this.IsRequired) }
        };
    switch (this.Datatype) {
        case 'number':
            $.extend(true, cm, { template: numberTemplate });
            lastFieldName = cm.name; //Store the fieldName.
            break;
        case 'DateTime':
            $.extend(true, cm, { template: dateTemplate });
            lastFieldName = cm.name;
            break;
        case 'dropdown':
            var values = this.ValueList.slice(0, -1);
            $.extend(true, cm, {
                template: dropdownTemplate,
                editoptions: { value: ":Select;" + values, defaultValue: this.DefaultValue },
                searchoptions: { value: ":All;" + values }
            },
            this.ValueType == "F" ? { label: this.ValueId } : {} );
            break;
        default:
            break;
    }
    if (cm)
    colname.push(cm);
});

//Binding grid Starts.
$("#TransactionsGrid").jqGrid({
    //data: mydata,
    datatype: "local",
    hoverrows: false,
    colModel: colname,
    rowNum: 10,
    rownumbers: true,
    pager: "#TransactionsPager",
    localReader: { id: "TransactionId" },
    prmNames: { id: "TransactionId" },
    viewrecords: true,
    caption: "Transaction Details",
    height: "auto",
    gridview: true,
    autoencode: true,
    ignoreCase: true,
    cmTemplate: { width: 100 },
    onInitGrid: function () {
        // get reference to parameters
        var p = $(this).jqGrid("getGridParam");

        // set data parameter
        p.data = mydata;
    }
});
Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks for your valuable response , Also i need to simplify the switch case used in the script so that i can build the object array easily. Now the readability and the code is complex. – Habeeb Oct 01 '14 at 05:15
  • @HbV2: You are welcome! You wrote "i need to simplify the switch case used in the script". I don't understand what you mean. Probably you should post a part of the code where you have problems. I would recommend you additionally to use `templates` in `colModel`. See [the answer](http://stackoverflow.com/a/6047856/315935). It can simplify the code. – Oleg Oct 01 '14 at 05:38
  • I updated the Question. Apart from templates what can i do to make it simple. – Habeeb Oct 01 '14 at 05:49
  • @HbV2: I will append my answer later with my suggestion how to reduce/optimize by usage of column templates. I should remark, but such changes will reduce the code, make it more readable and maintainable, but *it will do less for performance* of your page. The suggestions which I posted initially can do improve performance of the grid especially if it have many rows. How many rows in the grid you have typically? Which web browser is the main browser for you? – Oleg Oct 01 '14 at 06:19
  • Thanks a lot. The rows will be around 1000 to 5000 and columns will be around 50 to 100. This grid will be responsive. Major broswers we use are chrome, ie, safari, firefox. – Habeeb Oct 01 '14 at 06:27
  • Updated my question for the cases that i'm going to use. Kindly have a look into that too. Thanks – Habeeb Oct 01 '14 at 07:28
  • @HbV2: You are welcome! I updated my answer (see **UPDATED** part and the demo http://jsfiddle.net/z1ujyh02/6). It's important that you fix additionally the values of name property: spaces and dots should be removed. – Oleg Oct 01 '14 at 09:27
  • Kindly look into this "http://stackoverflow.com/questions/26271602/file-upload-in-jqgrid-inline-edit" – Habeeb Oct 09 '14 at 06:24
  • Kindly see the link, http://stackoverflow.com/questions/26271602/file-upload-in-jqgrid-inline-edit. – Habeeb Oct 14 '14 at 09:35
  • @HbV2: I don't use `editype: 'file'` myself so I can't help you in solving of the problem. In any way you need use some **additional** component/plug for the file upload. jqGrid just set only the `type` attribute to `"file"`. It's not enough for uploading of the file. – Oleg Oct 14 '14 at 09:43
  • Do u have any sample or references for fileupload column? – Habeeb Oct 14 '14 at 11:26
  • @HbV2: I wrote that I didn't used `editype: 'file'` myself. Search just for `enctype="multipart/form-data"`. Typically one need to have `
    ` with `method="POST" enctype="multipart/form-data"` attributes to upload files, but there are some variations, there are plugins which can help.
    – Oleg Oct 14 '14 at 11:33
  • @HbV2: I forgot to mention `FormData` class which supports many modern web browsers (IE only starting with IE10) and which can be used close to `$.serialize` see [the answer](http://stackoverflow.com/a/20863123/315935) and [this one](http://stackoverflow.com/a/5976031/315935). – Oleg Oct 14 '14 at 12:20
  • Please help on this. http://stackoverflow.com/questions/30529056/jqgrid-file-upload-with-form-edit – Habeeb May 29 '15 at 12:26
  • @HbV2: Sorry, but I didn't need to do file upload in any my projects for customers. I know that you need to use some *additional* upload plugin. You can't use just only jqGrid functionality. For example [this one](http://www.plupload.com/) is powerful enough, but I repeat that I don't use the feature myself. You should search in Internet for file upload plugins which the mostly corresponds to your requirements. – Oleg May 29 '15 at 18:58