AaA
AaA

Reputation: 3694

jqGrid get row data on custom button click

I have following custom grid

grid screenshot

I need to get rowObject when user clicks the image in Serial column to show a dialog allowing user to select another serial from available list for that row and then send the selected serial back to server.

As the images on column 5 and 6 execute functions related to data in their column, I cannot combine all images to a single action column with edit and delete buttons thus this answer is not suitable for me.

Currently I'm using following method to find desired row and call my function with row data. This method is slow as it has to go through data in a for loop and find the matching record. I stripped out all unrelated code and here is the rest

    var TerminalColNames = [
        'id',
        'Serial'
    ];

    var TerminalColModel = [
        { name: 'id', width: '180px', formatter: TerminalID_Formatter},
        { name: 'serial', width: '160px', formatter: Formatter, sortable: false }
    ];

    function TerminalID_Formatter(cellvalue, options, rowObject) {
        return ' ' +
            '<img src="pencil.png" onclick="return edit(\'' + cellvalue + '\')"> ' +
            '<img src="bin.png"    onclick="return delete(\'' + cellvalue + '\')"> ' +
            cellvalue;
    }

    function Formatter(cellvalue, options, rowObject) {
        return '<img src="link.png" onclick="return bind(\'' + rowObject.id + '\')"></a> ' + rowObject.serial.current;
    }

    function CreateGrid(TableElement, colNames, colModel, data) {

        $(TableElement).jqGrid({
            datatype: 'local',
            data: data,
            colNames: colNames,
            colModel: colModel,
            height: '150px',
            //onSelectRow: function (id, status, e) {
            //    rowData = $(this).jqGrid("getLocalRow", id);
            //    return RowAction(rowData);
            //}
        });
    }

    $(function () {
        CreateGrid('#TerminalGrid', TerminalColNames, TerminalColModel, data.terminals);
    });

    function RowAction(rowData) {
        alert('Row Action:' + JSON.stringify(rowData));
    }

    function bind(id) {
        for (i in data.terminals){
            if (data.terminals[i].id == id){
                return ProcessBind(data.terminals[i]);
            }
        }
        return false;
    }


    function ProcessBind(rowObject){
        if (rowObject.id)
            alert('Bind:' + rowObject.serial.avail.length);
        else 
            alert('Bind not found');
        return true;
    }

    var data = {
        "id": "1234",
        "terminals": [
            {
                "id": "111111",
                "serial": {
                    "current": "888888",
                    "avail": [
                        "444444",
                        "555555",
                        "666666"
                    ]
                }
            },
            {
                "id": "777777",
                "serial": {
                    "current": "333333",
                    "avail": [
                        "999999",
                        "000000",
                    ]
                }
            },
            //.....
        ]
        //.....
    }

I didn't use $(this).closest('tr').attr('id') because I believe it is much slower as it has to go through DOM to find the id and then go through the JSON data to find the row data. It also needs key: true to be set in id column.

Question

Is there a better method to get the record data? Or is there a jqGrid method to return rowIndex in JSON array?

EDIT I forget to mention that I'm using oleg's free jqgrid 4.15.2

Upvotes: 1

Views: 4650

Answers (2)

Oleg
Oleg

Reputation: 221997

First of all I'd recommended you to make some minor fixes in your code:

  • change the properties width: '180px' to width: 180 and the option height: '150px' to height: 150. The current code works, but it's misunderstandable because width: '180em' will be interpreted as width: 180 (or 180px), but height: '150em' will really increase the height of the grid.
  • one should reduce the number of global functions in JavaScript code. If CreateGrid function for example be used only once inside of $(function () {...}); and var data only inside of CreateGrid then you should move the declaration of variables/functions inside of the corresponding scope.

Now about your main question. Event parameter of beforeSelectRow, onSelectRow or onCellSelect callbacks provides all information, which you need. target property is the DOM element clicked inside of the grid. One can test its class, tagName, name or other properties to verify that specific image/icon is clicked. One don't need to use onclick attribute.

About the performance. It's important to understand that access of properties of DOM element (class, tagName, name, parentElement and so on) is very quickly. The time to access of the properties isn't depend on the total number of elements on the page. It makes the working of closest, hasClass and other functions very quickly. It's recommended way. The below code provides an example of accessing to the full row data:

onSelectRow: function (rowid, status, e) {
    var $self = $(this), $target = $(e.target),
        p = $self.jqGrid("getGridParam"),
        rowData = $self.jqGrid("getLocalRow", rowid),
        $td = $target.closest("tr.jqgrow>td"),
        iCol = $td.length > 0 ? $td[0].cellIndex : -1,
        cmName = iCol >= 0 ? p.colModel[iCol].name : "";

    switch (cmName) {
        case "id":
            if ($target.hasClass("myedit")) {
                alert("edit icon is clicked in the row with rowid=" + rowid);
            } else if ($target.hasClass("mydelete")) {
                alert("delete icon is clicked in the row with rowid=" + rowid);
            }
            break;
        case "serial":
            if ($target.hasClass("mylink")) {
                alert("link icon is clicked in the row with rowid=" + rowid);
            }
            break;
        default:
            break;
                  }
    alert("full row data:\n\n" + JSON.stringify(rowData));
    //    return RowAction(rowData);
}

See https://jsfiddle.net/OlegKi/dfra7snb/

Code snippet:

$(function () {
    "use strict";
    function CreateGrid(TableElement, colNames, colModel, data) {
        $(TableElement).jqGrid({
            datatype: 'local',
            data: data,
            colNames: colNames,
            colModel: colModel,
            iconSet: "fontAwesome",
            onSelectRow: function (rowid, status, e) {
                var $self = $(this), $target = $(e.target),
                    p = $self.jqGrid("getGridParam"),
                    rowData = $self.jqGrid("getLocalRow", rowid),
                    $td = $target.closest("tr.jqgrow>td"),
                    iCol = $td.length > 0 ? $td[0].cellIndex : -1,
                    cmName = iCol >= 0 ? p.colModel[iCol].name : "";

                switch (cmName) {
                    case "id":
                        if ($target.hasClass("myedit")) {
                            alert("edit icon is clicked in the row with rowid=" + rowid);
                        } else if ($target.hasClass("mydelete")) {
                            alert("delete icon is clicked in the row with rowid=" + rowid);
                        }
                        break;
                    case "serial":
                        if ($target.hasClass("mylink")) {
                            alert("link icon is clicked in the row with rowid=" + rowid);
                        }
                        break;
                    default:
                        break;
                              }
                alert("full row data:\n\n" + JSON.stringify(rowData));
                //    return RowAction(rowData);
            },
            height: 150
        });
    }
    var TerminalColNames = [
        'id',
        'Serial'
    ];

    function TerminalID_Formatter(cellvalue, options, rowObject) {
        return '<span class="fa fa-pencil fa-lg myedit" aria-hidden="true"></span>' +
            '<span class="fa fa-trash-o fa-lg mydelete" aria-hidden="true"></span>' +
            cellvalue;
    }

    function Formatter(cellvalue, options, rowObject) {
        return '<span class="fa fa-link fa-rotate-90 fa-lg mylink" aria-hidden="true"></span>' +
            rowObject.serial.current;
    }
    var TerminalColModel = [
        { name: 'id', width: '180em', formatter: TerminalID_Formatter},
        { name: 'serial', width: 160, formatter: Formatter, sortable: false }
    ];
    var data = {
        "id": "1234",
        "terminals": [
            {
                "id": "111111",
                "serial": {
                    "current": "888888",
                    "avail": [
                        "444444",
                        "555555",
                        "666666"
                    ]
                }
            },
            {
                "id": "777777",
                "serial": {
                    "current": "333333",
                    "avail": [
                        "999999",
                        "000000",
                    ]
                }
            },
            //.....
        ]
        //.....
    };
    CreateGrid('#TerminalGrid', TerminalColNames, TerminalColModel, data.terminals);
});
.myedit, .mydelete, .mylink {
    margin: 0 0.25em;
}
.myedit {
    color: green;
}
.mydelete {
    color: red;
}
.mylink {
    color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.min.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/free-jqgrid/4.15.2/css/ui.jqgrid.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/free-jqgrid/4.15.2/jquery.jqgrid.min.js"></script>

<table id="TerminalGrid"></table>

Upvotes: 2

Tony Tomov
Tony Tomov

Reputation: 3277

If I understand correct you can use the method getLocalRow( rowid ) in case you use the local data. This method return quick the rowdata by index when the rowid is know.

Another trick is to use the internal _index jqGrid parameter to obtain the index of the row by given row id.

var grid = $("#jqGrid")[0];
var rowid = "somerowid";
var rowIndex = grid.p._index[rowid];

var datarow = grid.p.data[rowIndex];

The method getLocaRow use similar approach.

In case the data is not local you can use getInd method

The methods here are used in Guriddo jqGrid. More on the methods can be found Guriddo Documentation

Upvotes: 1

Related Questions