0

Free Jqgrid has actions column. colmodel:

{"hidden":false,"label":"","name":"_actions","width":72
,"align":"left","template":"actions","fixed":false,"resizable":true,
  "formatoptions":{"editbutton":true,"delbutton":true,"delOptions":{"url":"Delete" }}},

{"label":"Nimetus","name":"Nimi","index":"Nimi","editoptions":{"maxlength":80,"size":80 }

It is populated from remote json data like

{"total":1,
 "page":1,
  "rows":[{"id":"2ARVELDUSARV", "cell":[null,"2ARVELDUSARV"]},
          {"id":"ACME","cell":[null,"ACME"]},
          {"id":"KAKSKOERA","cell":[null,"KAKSKOERA"]}
 ]
}

In cell array first column is not used. If this column is removed, jqgrid does not render data correctly since this column presence is required as placeholder for actions column. How to fix this so that jqgrid will accept data without first column:

{"total":1,
 "page":1,
  "rows":[{"id":"2ARVELDUSARV", "cell":[null,"2ARVELDUSARV"]},
          {"id":"ACME","cell":["ACME"]},
          {"id":"KAKSKOERA","cell":["KAKSKOERA"]}
 ]
}

Update

I looked for data format change as recommended in answer. jqgrid data is created from sql select statement in ASP.NET MVC4 using code below. Web API serializes this to format for json for jqgrid automatically.

How to create result which can serialized to propertyname: value format recommended in answer ?

  object GetDataForJqGrid() {
        IDbConnection conn;
        using (var dataReader = DataAccessBase.ExecuteReader(sql.ToString(), out conn,
               CommandBehavior.CloseConnection | CommandBehavior.SingleResult,
               sql.GetParameters.ToArray()))
        {
            var rowList = new List<GridRow>();
            var pkeys = DatabasePrimaryKey();
            while (dataReader.Read())
            {
                var pkv = new List<object>();
                int offset = 1; // required for actions column
                var row = new GridRow
                {
                    id = IdHelper.EncodeId(pkv),
                    cell = new object[dataReader.FieldCount + offset + imageCount]
                };
                for (int j = 0; j < dataReader.FieldCount; j++)
                   row.cell[offset + j] = dataReader.GetValue(j);
                rowList.Add(row);
            }

            return new
            {
                total = rowList.Count() < rows ? page : page + 1,                                  page, 
          rows = rowList
            };
}

public class GridRow
{
    public string id;
    public object[] cell;
}
Andrus
  • 26,339
  • 60
  • 204
  • 378

1 Answers1

1

The most easy way would be to chanege the format of data returned from the server to use repeatitems: false style of the data. I mean the usage of

{
    "total": 1,
    "page": 1,
    "rows": [
        { "id": "2ARVELDUSARV", "Nimi": "2ARVELDUSARV" },
        { "id": "ACME", "Nimi": "ACME" },
        { "id": "KAKSKOERA", "Nimi": "KAKSKOERA"}
    ]
}

or, after adding key: true to the definition of the column Nimi

{
    "total": 1,
    "page": 1,
    "rows": [
        { "Nimi": "2ARVELDUSARV" },
        { "Nimi": "ACME" },
        { "Nimi": "KAKSKOERA"}
    ]
}

instead of

{
    "total": 1,
    "page": 1,
    "rows": [{
        "id": "2ARVELDUSARV",
        "cell": ["2ARVELDUSARV"]
    }, {
        "id": "ACME",
        "cell": ["ACME"]
    }, {
        "id": "KAKSKOERA",
        "cell": ["KAKSKOERA"]
    }]
}

Alternatively one can use jsonReader: { repeatitems: false } event with your current format of data and add jsonmap: "cell.0" property to, which means getting the first element (index 0) from the array cell:

$("#list").jqGrid({
    datatype: "json",
    url: "andrus.json",
    colModel: [
        { label: "", name: "_actions", template: "actions" },
        { label: "Nimetus", name: "Nimi", jsonmap: "cell.0" }
    ],
    iconSet: "fontAwesome",
    jsonReader: { repeatitems: false }
});

see the demo.

I personally would recommend you don't use your original format (cell with array of values) and use just the named property with additional id property (if id value is not included in the item already). If you would do use the solution with jsonmap you should be carefully with changing the order of the columns (using remapColumns) and later reloading of data. You could required to update jsonmap values after the changing the column order. Thus I repeat that I recommend you to change format of data returned from the server.

UPDATED: The Updated part of your question formulate absolutely new question which have no relation with jqGrid. It's pure C# problem. Nevertheless I try to answer, because I use C# too.

What you can do with minimal changes of your code is the following: You should add using System.Dynamic; and using System.Linq; first of all. Then you should replace the code inside of using (...) {...} to about the following

var rowList = new List<dynamic>();
while (dataReader.Read()) {
    var row = new ExpandoObject() as IDictionary<string, object>;
    for (int j = 0; j < dataReader.FieldCount; j++) {
        if (!dataReader.IsDBNull(j)) {
            row.Add(dataReader.GetName(j), dataReader.GetValue(j));
        }
    }
    rowList.Add(row);
}

Serializing of rowList will produce the names properties. If you know the primary key of the data, then you can add id property with the corresponding value in the same way (using row.Add("id", IdHelper.EncodeId(pkv))). I don't included the part because the code which you posted is not full and pkv is currently always new List<object>(), which is wrong. If the data have composed key (multiple value set is unique) then you can make string concatenation of the keys using '_' (underscore) as the separator.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I tried to change data format but don't know how to create it so that it can properly serialized by Web API. I updated question. – Andrus Dec 05 '15 at 17:06
  • It is possible to add columnNames property to json response. This contains all column names in result array. It can saved in local storage and verified before restoring state. This avoids property name duplication for every row and makes data size much smaller. – Andrus Dec 05 '15 at 19:04
  • @Andrus: The **"Update"** part of your question formulate **absolutely new question**, which have no direct relation with jqGrid. It's pure C# problem. Nevertheless I try to answer it in **UPDATED** part of my answer. – Oleg Dec 05 '15 at 20:28
  • Thank you. Great update. I found similar solution in http://www.codeproject.com/Tips/1050214/Entity-Framework-How-to-retrieve-dynamic-data – Andrus Dec 05 '15 at 20:31
  • @Andrus: It's interesting! The code is really very close, but I wrote my code independent. I think that it's really native to use `ExpandoObject` in the code. By the way, the code from the comment to [the post](http://www.codeproject.com/Tips/1050214/Entity-Framework-How-to-retrieve-dynamic-data) looks better for me. I mean that `params DbParameter[] parameters` is better as `Dictionary Parameters` – Oleg Dec 05 '15 at 20:49
  • New data format worked. Thank you. However column state restore still causes invalid data posting if new column is added to colmodel after state is saved. – Andrus Dec 05 '15 at 22:01
  • Composite primary key may contain `_` and other similar characters as part of its value. So `_` cannot used for concatenation. How to create proper `id` in this case? – Andrus Dec 05 '15 at 22:17
  • @Andrus: There are no universal way to create proper `id`. I personally construct mostly the Queries or the results of Stored Procedures (used in `ExecuteReader`) so that they have `id` property. I construct the `id` using some unique column or composed key. In the way I'm able always to solve the problem, but the solution is on the previous step: on the step of construction `sql` parameter (see your code) – Oleg Dec 05 '15 at 22:36
  • `Nimi` column can contain any values, which may differ only by case and may be empty string for one row. If `key: true` is used, will jqgrid allow such key column? Earlier this was not allowed as discussed in http://stackoverflow.com/questions/6170325/jqgrid-how-to-update-row-id-if-primary-key-columns-was-edited and in http://stackoverflow.com/questions/7230179/how-to-allow-to-use-case-sensitive-row-ids-in-jqgrid – Andrus Dec 06 '15 at 07:21
  • @Andrus: It seems that we come back to an old discussion. You hold the data in the database? Which primary key you have for the data? I insert in almost every table the column IDENTITY (see [here](http://www.w3schools.com/sql/sql_autoincrement.asp)). It is the best was to have id for every item (row) of data. One will don't need to change the id in grid. Thus I never have the problem which you describe. – Oleg Dec 06 '15 at 09:17
  • C# code in answer creates whole response in memory. Is it reasonable to refactor is using yield statement ? In this case data is read only as needed – Andrus Dec 26 '15 at 16:23
  • @Andrus: You can of cause use `async` in the web method and to use asynchronous versions of methods like `await dataReader.ReadAsync()` instead of `dataReader.Read()`. See [the answer](http://stackoverflow.com/a/34162630/315935) for more code fragments. – Oleg Dec 26 '15 at 16:29