1

Ideally I would call setRowData and have my cell formatters and rowattr function re-run, but cell formatters and rowattr functions don't re-run when calling setRowData (I don't know why but that's another question maybe), so setRowData isn't really helpful for me.

It seems the next easiest thing to do would be to remove a row and re-add a new one at the same position with the same model. To do that I need to get the rowid of the row above the selected row so that I can call addRowData and specify the ID of the row above in srcrowid and use 'after' for the position. This is what I'm thinking:

$.jgrid.extend({
    updateRow: function(rowid, model){
        // get index from id
        var index = this.jqGrid('getInd', rowid);

        // note: my first row's index is 1 (is that normal?)
        if ( index == 1 ){
            position = 'first';
            srcrowid = 'n/a';
        }
        else{
            position = 'after';
            srcrowid = _____ how to get rowid of row above selected row _____???
        }

        // delete row
        this.jqGrid('delRowData', rowid);

        // insert at index
        this.jqGrid('addRowData', rowid, model.attributes, position, srcrowid);
    }
});

How can I get the rowid of the row above the selected row? (Is there an easier way? Is this a bad strategy?)

Note: I'm using backbone.js collections and models

jbobbins
  • 1,221
  • 3
  • 15
  • 28
  • What attributes you assign by `rowattr`? Is it attributes which need be combined with existing attributes of the row (like `class` or `style`) or which replaces the attributes (like `title`, `id`, `tabindex` or other)? The common solution could be long, but if you would specify what you do exactly then you can solve your problem with call of `rowattr` after `setRowData` relatively easy. – Oleg Apr 30 '15 at 08:10
  • @Oleg This case is `class` or `style`. But I have both `rowattr` function and column formatters. Also I'm looking for a generic function that's robust enough for any future usage (referring to the extension I included above). Regarding specifically finding a row, I was *hoping* there was a built in jqGrid function I missed like `getRowIDFromRowIndex`. But maybe I just have to use jQuery?....like `$(this).find('tr#' + rowid).prev()[0]` – jbobbins Apr 30 '15 at 15:26
  • `$(this).find('tr#' + rowid).prev()[0].id` to get the id itself is what I was really going for I guess – jbobbins Apr 30 '15 at 15:34
  • It seems that there a misunderstanding what is `rowid`, what is `rowIndex`. It could be important to know **how you fill the grid**. Which `datatype` you use. Are the input data for the grid in "array of strings" format `["foo", "bar", "bla"]` or you use object style: `{id:123, name: "abc", col1: "xyz"}`? Hoy you specify `id` in the input data? How many rows have the grid? If you have local data and use `gridview: true` option, display 10-50 rows then repainting of the whole grid with `reloadGrid` could take practically the same time like modification of one row of data. – Oleg Apr 30 '15 at 16:03
  • In general one can use just `$("#" + rowid).addClass("yourClassName")` or `$("#" + rowid).css(yourStyles)` or `$("#" + rowid).attr(attrName, attrValue)` to assign classes, styles or attributes. – Oleg Apr 30 '15 at 16:05
  • I'm pretty sure I understand what is rowid and rowindex: rowid is the ID of the row (in my case it's actually a uuid). rowindex is the position of the row. Correct? Where do you think the misunderstanding is? Are you saying the `srcrowid` param of `addRowData` is expecting a rowindex (position)?? If so, then why does it have 'id' in the name?..... I use object style (backbone model.attributes) for the row data. I have `gridview: true` This current grid has 20-500 rows. – jbobbins Apr 30 '15 at 16:43
  • I know I can use .addClass or .css, but it means doing the same things twice: once that way and once in the formatters and rowattr function. (I appreciate your time and help on this question, Oleg--thanks!) – jbobbins Apr 30 '15 at 16:45

2 Answers2

2

I find the best way to change the row is to use setRowData instead of usage delRowData and addRowData. If you know rowid then you can use $("#" + rowid); (or if rowis have special characters like :, . an so on then $("#" + $.jgrid.jqID(rowid));) to get the <tr> element. Then you can use jQuery.addClass, jQuery.css, jQuery.attr to change the attributes of the row.

It's important to understand that jqGrid uses the same methods internally it it's required to modify element of the grid. The main goal of rowattr is another one. During filling of the grid data there are many scenarios. One can create DOM elements for <td> and <td> and insert there in the grid. The main problem is performance in case of working with DOM. It's much slowly as building of strings. Moreover DOM is even much more slowly if the elements are exist on the the HTML page (in opposite to disconnected elements). If one modify one element only from the grid having 500 rows then the position of elements of all other rows need be recalculated.

Because of the problem jqGrid construct the whole body of the grid first in string format and then assign all <tr> and <td> elements using one set of innerHTML. It improves dramatically the performance of filling of the grid. See the answer for additional information. The formatters and callbacks cellattr and rowattr are introduced to allow to customize cell and row attributes during building of grid body in string format. It gives you customization possibilities without reducing of performance.

On the other side if you need to modify the row which are attached already on HTML page then you will have no advantage with working with strings instead of DOM. Because of that I recommend you just use jQuery.addClass, jQuery.css, jQuery.attr directly. If you need to change multiple classes, assign multiple css rules or multiple attributes then you should use one call of above functions. You can use object form of jQuery.css, jQuery.attr for it.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks Oleg. It seems to be an effective jqGrid user, you need to have a lot of knowledge. I appreciate you taking the time to share yours! – jbobbins Apr 30 '15 at 20:24
  • 1
    @jbobbins: Is the code of `rowattr` so long? I'm don't believe that it's so complex that it's different to write the second function which do the same. Moreover you can share the main part of the complex code in the third function. The function will analyse the rowdata and generate information about classes, css styles and attributes which need be set. The `rowattr` can just convert the information to the format which require `rowattr` and another function will use `$.addClass`, `$.css`, `$.attr` to *apply* the changes to one row of the grid. – Oleg Apr 30 '15 at 20:58
0

The updateRow extension below works, BUT I ended up not using it. Not so much for the reasons Oleg talked about (which I assume are valid and something you should definitely consider), but because I had a filter provider that was too difficult to sync with (e.g. after soft deleting a row, I need to now determine if new deleted status agrees with current filter...and that's a pretty simple example). So I just defer to the data the filter provider gives me and repopulate the grid each time, which I'm not fond of, but I don't see other easy options.

As far as the extension below goes, here are pros/cons as I see them:

Pros:

  • easy to use
  • You just rely on the rowattr functions and cell formatters you already defined. You don't have to write those twice.

Cons:

  • possibly performance--see Oleg's answer
  • please add any you see

Unknowns:

  • performance? I have no idea how much worse it performs. It would be interesting to do benchmarks with different browsers. I saw no problems, but I only have maybe 20 rows. Let's say we're working with 500 rows and adding/removing classes and calling .css() took 30 ms but using the extension took 300 ms on a 'typical' machine/browser. That would be 10 times slower, but for me it would probably be worth it because I don't have to write something twice.

here's the extension:

$.jgrid.extend({
    updateRow: function(rowid, data){
        // get index from id
        var index = this.jqGrid('getInd', rowid);

        // note: my first row's index is 1 (is that normal?)
        if ( index == 1 ){
            position = 'first';
        }
        else{
            position = 'after';
            srcrowid = $(this).find('tr#' + rowid).prev()[0].id;
        }

        // delete row
        this.jqGrid('delRowData', rowid);

        // insert at index
        this.jqGrid('addRowData', rowid, data, position, srcrowid);
    }
});
jbobbins
  • 1,221
  • 3
  • 15
  • 28
  • How many rows from 500 you want to update? If you need update *only one row* then you have no performance problems at all. Reloading of the whole grid is quickly only if you use **local data** (`datatype: "local"` or `datatype: "local"` **with** `loadonce: true`). In the case you will have all the 500 rows locally and to use probably *local* paging. In the case you can just replace `data` parameter of jqGrid and trigger `reloadGrid`. – Oleg Apr 30 '15 at 20:52
  • typically only need to update 1 row. yes, it is `datatype: 'local'` and `loadonce: true`. The doc for trigger(“reloadGrid”) says "IT'S WORK ONLY IF loadonce: false !!!": http://www.trirand.com/jqgridwiki/doku.php?id=wiki:methods – jbobbins Apr 30 '15 at 21:46
  • You interpret the information not correctly. If one uses `datatype: 'json', loadonce: true` then jqGrid changes `datatype` automatically to `datatype: 'local'` *after the first load*. Thus `reloadGrid` will work *locally* and will not reload the data from the server. On the other side you can try to use `.jqGrid("getLocalRow", rowid)` to get **the reference** to internal data of the item. Then you can modify the item and make `.trigger("reloadGrid")` or `.trigger("reloadGrid", [current: true])`. You will see modified data in the grid. reloadGrid will be called on local paging and filtering too – Oleg Apr 30 '15 at 22:03