1

I am trying to create a jqGrid with MVC4 WebApi. I have looked through various example and finally using this link as reference. The issue is grid is not populating with data but it is hitting server's GET method(Kept breakpoint there to test). I have hosted my app on local IIS. Below is jqgrid page(index.htm)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>My First Grid</title>
    <link href="../Content/jquery.jqGrid/ui.jqgrid.css" type="text/css" rel="stylesheet" />
    <style>
        html, body {
            font-size: 75%;
        }
    </style>
    <script src="../Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
    <script src="../Scripts/jquery-ui-1.10.4.js" type="text/javascript"></script>
    <script src="../Scripts/i18n/grid.locale-en.js" type="text/javascript"></script>
    <script src="../Scripts/jquery.jqGrid.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(document).ready(function () {
            var API_URL = "/WebApiOne/api/task/";
            jQuery("#gridMain").jqGrid({
                url: API_URL,
                data : API_URL,
                datatype: 'json',
                contentType: "application/json; charset=UTF-8",
                mtype: 'GET',
                pager: '#pagernav',
                sortable: true,
                height: 200,
                viewrecords: true,
                colNames: ['TaskID', 'ProjectID', 'ProjectName', 'TaskName', 'TaskStatus'],
                colModel: [{ name: 'TaskID', index: 'TaskID', width: 40, sorttype: "int" },
                 { name: 'ProjectID', index: 'ProjectID', editable: true, edittype: 'int', width: 70 },
                 { name: 'ProjectName', index: 'ProjectName', editable: true, edittype: 'text', width: 70 },
                 { name: 'TaskName', index: 'TaskName', editable: true, edittype: 'text', width: 50, align: "right" },
                 { name: 'TaskStatus', index: 'TaskStatus', editable: true, edittype: 'text', width: 50, align: "right"}
                ],
                caption: "CRUD With ASP.NET Web API",
                autowidth: true
            });
        });
    </script>
</head>
<body>

    <table id="gridMain">
    </table>
    <div id="pagernav">
    </div>
</body>
</html>

Here is my Server Side Code :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace WebApiOne.Controllers
{
    public class Task
    {
        public int TaskID { get; set; }
        public int ProjectID { get; set; }
        public string ProjectName { get; set; }
        public string TaskName { get; set; }
        public string TaskStatus { get; set; }
    }

    public class TaskController : ApiController
    {
        // GET api/task
        public IEnumerable<Task> Get()
        {
            Task[] tasks = new Task[2];

            tasks[0] = new Task()
            {
                TaskID = 1,
                ProjectID = 1,
                ProjectName = "ProjectOne",
                TaskName = "FirstPage Development",
                TaskStatus = "InProgress"

            };

            tasks[1] = new Task()
            {
                TaskID = 2,
                ProjectID = 1,
                ProjectName = "ProjectOne",
                TaskName = "Second Page Development",
                TaskStatus = "Yet To Start"

            };

            return tasks;
        }

        // GET api/task/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/task
        public void Post([FromBody]string value)
        {
        }

        // PUT api/task/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/task/5
        public void Delete(int id)
        {
        }
    }
}

But When I browse for localhost/WebApiOne/api/task/ I get raw data in json format as :[{"TaskID":1,"ProjectID":1,"ProjectName":"ProjectOne","TaskName":"FirstPage Development","TaskStatus":"InProgress"},{"TaskID":2,"ProjectID":1,"ProjectName":"ProjectOne","TaskName":"Second Page Development","TaskStatus":"Yet To Start"}]

It proves that Server is functional and I am missing something on front end.

mikus
  • 3,042
  • 1
  • 30
  • 40
Sandeep Kushwah
  • 590
  • 1
  • 18
  • 35
  • Which version of jqGrid you use? Is `TaskID` value is different in all items returned by `WebApiOne/api/task/` (can `TaskID` be used as rowid)? – Oleg Sep 17 '15 at 14:07
  • version - @license jqGrid 4.4.4 - jQuery Grid – Sandeep Kushwah Sep 17 '15 at 14:09
  • Yes.. TaskID is different in all items returned by `WebApiOne/api/task/` – Sandeep Kushwah Sep 17 '15 at 14:10
  • @Oleg : I have installed jqgrig in my VS2012 using package manager console with this command **Install-Package jQuery.jqGrid** – Sandeep Kushwah Sep 17 '15 at 14:12
  • Good tutorial for JQGRID - http://www.codeproject.com/Articles/822405/Using-jqGrid-in-an-MVC-Web-Application – Sandeep Kushwah Sep 18 '15 at 09:53
  • I agree, that the article can be helpful for understanding how jqGrid works. I read it shortly after publishing and have found a lot of small errors and things which I found not good. So I wrote my comment http://www.codeproject.com/Articles/822405/Using-jqGrid-in-an-MVC-Web-Application?msg=4914798#xx4914798xx – Oleg Sep 18 '15 at 10:09
  • @Oleg : I will go through your recommendations mentioned there. and you got my project? I sent the google drive link over stackoverflow chat – Sandeep Kushwah Sep 18 '15 at 10:13
  • I found it now. I have to do some things for my customer now, but I will send you the modified demo later. – Oleg Sep 18 '15 at 12:24
  • I posted modified demo under http://www.ok-soft-gmbh.com/jqGrid/OK/WebApiOne.zip You should set breakpoints inside of server code and use Fiddler to see that all requests works as expected. I used URLs from CDN (see [here](https://github.com/free-jqgrid/jqGrid/wiki/Access-free-jqGrid-from-different-CDNs)), but for intranet solution you can use local files instead. The server code should implement delete/edit/add in database of cause. After editing the data will be reloaded from server to be sure that one use the last data and server side id after Add be assigned. – Oleg Sep 18 '15 at 15:25
  • I used `reloadGridOptions: { fromServer: true }` to force reloading from **server** after editing. You can of cause add custom editing options inside of `formEditing` or `formDeleting`. For example you can place `closeAfterAdd: true, closeAfterEdit: true` inside of `formEditing`. The new style of editing options are described in [the wiki article](https://github.com/free-jqgrid/jqGrid/wiki/New-style-of-usage-options-of-internal-methods). I added the usage of Font Awesome too (see [the wiki](https://github.com/free-jqgrid/jqGrid/wiki/Using-Font-Awesome-in-free-jqGrid-4.8)) – Oleg Sep 18 '15 at 15:29

2 Answers2

1

I recommend you don't use old versions of jqGrid like version 4.4.4 published more as 2.5 years ago. I would recommend you to use the current version (4.9.2) of free jqGrid. If you use prefer to use NuGet, then you can use Install-Package free-jqGrid to install the current version of free jqGrid (see here). See the wiki and readme to every published version for additional information.

Some changes can be used independent from the version of jqGrid:

  • data : API_URL should be removed if you use datatype: 'json'.
  • contentType is the option of jQuery.ajax. If you need to set it in jqGrid you should use ajaxGridOptions: {contentType: "application/json; charset=UTF-8"}.
  • if you use old version of jqGrid then you need add jsonReader in the form jsonReader: {repeatitems: false, root: function (obj) { return obj; }}. If you use free jqGrid then it will detect the structure of your currect JSON response automatically and no jsonReader is required.
  • You should add loadonce: true option if you plan don't implement server side paging and sorting of data. You should return all the data and once and jqGrid will do sorting, paging and filtering on the client side.
  • if you use old version of jqGrid you should add gridview: true to improve the performance. Free jqGrid use the option as default.
  • I would recommend you to use height: "auto" instead of height: 200, but the best choice depends on your exact requirements.
  • You should add autoencode: true option if the data returned from the server are pure data and not HTML fragments for the cells.
  • I recommend you remove unneeded index properties from colModel and the values with default values (edittype: 'text').
  • You should add key: true property to TaskID column. Input data have to contains information about rowid. Especially to be able to edit the data you should use correct rowid values.
  • if you use free jqGrid then you can remove <div id="pagernav"></div> and replace pager: '#pagernav' with pager: true option. Free jqGrid can automatically create the required <div> for the pager.

UPDATED: The server code could be modified to the following for example:

using System.Collections.Generic;
using System.Web.Http;

namespace WebApiOne.Controllers
{
    public class Task
    {
        public int TaskID { get; set; }
        public int ProjectID { get; set; }
        public string ProjectName { get; set; }
        public string TaskName { get; set; }
        public string TaskStatus { get; set; }
    }

    public class TaskController : ApiController
    {
        // GET api/task
        public IEnumerable<Task> Get() {
            Task[] tasks = {
                new Task {
                    TaskID = 1,
                    ProjectID = 1,
                    ProjectName = "ProjectOne",
                    TaskName = "FirstPage Development",
                    TaskStatus = "InProgress"
                },
                new Task {
                    TaskID = 2,
                    ProjectID = 1,
                    ProjectName = "ProjectOne",
                    TaskName = "Second Page Development",
                    TaskStatus = "Yet To Start"

                }
            };
            return tasks;
        }

        // GET api/task/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/task
        public void Post ([FromBody]Task task)
        {
            //perform new Row Add to DB
            // task.TaskID will be 0 here
        }

        // PUT api/task/5
        public void Put (int id, [FromBody]Task task)
        {
            //perform Db Update
            // task.TaskID and id are identical
        }

        // DELETE api/task/5
        public void Delete (int id)
        {
            // Delete row in DB.
        }
    }
}

The client code can be

$(document).ready(function() {
    "use strict";
    var apiUrl = "/WebApiOne/api/task/";
    jQuery("#gridMain").jqGrid({
        url: apiUrl,
        editurl: apiUrl,
        datatype: "json",
        gridview: true,
        height: "auto",
        iconSet: "fontAwesome",
        autoencode: true,
        sortable: true,
        viewrecords: true,
        loadonce: true,
        prmNames: { id: "TaskID" },
        colNames: ["TaskID", "ProjectID", "ProjectName", "TaskName", "TaskStatus"],
        colModel: [
            { name: "TaskID", width: 60, key: true, editable: false, sorttype: "int" },
            { name: "ProjectID", width: 90 },
            { name: "ProjectName", width: 190 },
            { name: "TaskName", width: 170, align: "right" },
            { name: "TaskStatus", width: 170, align: "right" }
        ],
        cmTemplate: { editable: true },
        //autowidth: true,
        formEditing: {
            width: 400,
            reloadGridOptions: { fromServer: true },
            serializeEditData: function (postdata) {
                var copyOfPostdata = $.extend({}, postdata);
                if (postdata.TaskID === "_empty") { // ADD operation
                    postdata.TaskID = 0; // to be easy to deserialize
                }
                delete copyOfPostdata.oper; // remove unneeded oper parameter
                return copyOfPostdata;
            }
        },
        formDeleting: {
            mtype: "DELETE",
            reloadGridOptions: { fromServer: true },
            serializeDelData: function () {
                return ""; // don't send and body for the HTTP DELETE
            },
            onclickSubmit: function (options, postdata) {
                //var p = $(this).jqGrid("getGridParam"); // get reference to internal parameters
                //p.datatype = "json";
                options.url = apiUrl + encodeURIComponent(postdata[0]);
            }
        },
        pager: true
    }).jqGrid("navGrid", {}, {
        mtype: "PUT",
        onclickSubmit: function (options, postdata) {
            //var p = $(this).jqGrid("getGridParam"); // get reference to internal parameters
            //p.datatype = "json"; // reset datatype to reload from the server
            options.url = apiUrl + encodeURIComponent(postdata[this.id + "_id"]);
        }
    }).jqGrid("filterToolbar") // add searching toolbar for local sorting (bacsue of loadonce:true) in the grid
        .jqGrid("gridResize");
});

The above code uses free jqGrid with Font Awesome. The corresponding demo project you can load from here. You should set breakpoints inside of server code and use Fiddler to see that all requests works as expected. The server code should implement delete/edit/add in database of cause. It's important to understand that the demo are based on your original code and it don't modify any data in the database. After editing the data will be reloaded from server to be sure that one use the last data and server side id after Add be assigned. Because the data will be not saved in the database or modified on the server the data will be display unchanged in the grid after loading. It means just that the server code need be extended to support modifications of data. I wanted just show how to configure client part (jqGrid) to send correct requests to the server.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I am trying all the changes you have recommended, Will update you in some time and Thank you for awesome answer(completely elaborated) – Sandeep Kushwah Sep 17 '15 at 14:44
  • I have changed `repeatitems` to false in `jsonReader: {repeatitems: true, root: function (obj) { return obj; }}` as per the answer posted by you at link - http://stackoverflow.com/questions/3213984/jqgrid-giving-exception-when-json-is-attempted-to-be-loaded – Sandeep Kushwah Sep 17 '15 at 14:56
  • It worked!!! THANKS ALOT :D. Stack is preventing me to up vote it more than 1 time. Otherwise I would have upvoted it to 100. A grand SALUTE to you :) – Sandeep Kushwah Sep 17 '15 at 14:57
  • 1
    @SandeepKushwah: Sorry, `repeatitems: true` was of cause typing error. it should be `repeatitems: false`. If you use new versions of jqGrid then the value is not really important and it will by fixed by jqGrid automatically. I fixed `repeatitems` used in my answer. – Oleg Sep 17 '15 at 14:58
  • Now I am trying your `free-jqGrid` library. Apart from this Could you please give me a good reference to implement ADD/EDIT/DELETE functionality using MVC4 Web Api. – Sandeep Kushwah Sep 17 '15 at 15:01
  • @SandeepKushwah: For editing in your case you can add `prnNames: {id: "TaskID"}` option first of all. Then you should decide which editing mode (form editing, inline editing or cell editing) and in which form (for example inline editing of click, on double-click or usage `inlineNav` to add editing toolbar or usage of column with `formatter: "actions"` or `template: "actions"` in free jqGrid) you need. I recommend you to use [Fiddler](http://www.telerik.com/fiddler) or Developer Tools of IE/Chrome to make HTTP trace. You will **see** the data which will be send on Add/Edit/Delete . – Oleg Sep 17 '15 at 15:10
  • Okay. I am trying that now, If I face any issues that cannot be fixed by googling, I will post new question and give you the link.. – Sandeep Kushwah Sep 17 '15 at 15:15
  • @SandeepKushwah: There are some old posts which can be helpful for you, but the exact implementation of server part could a little depend on the editing mode which you choose. I don't find the good example with WebAPI now, but [the answer](http://stackoverflow.com/a/7365228/315935) and HTTP trace should help you. – Oleg Sep 17 '15 at 15:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89955/discussion-between-sandeep-kushwah-and-oleg). – Sandeep Kushwah Sep 17 '15 at 19:14
0

Add below code in your jqGrid definition

jsonReader : {
   repeatitems: false
},
Gagan Jaura
  • 710
  • 1
  • 5
  • 14
  • It should work. Try below code in your action. First change the return type for your action to JsonResult and add below code. `return Json(tasks, JsonRequestBehavior.AllowGet);` – Gagan Jaura Sep 17 '15 at 14:13
  • `return Json(tasks, JsonRequestBehavior.AllowGet);` is having some syntax errors – Sandeep Kushwah Sep 17 '15 at 14:17