2

This is my first attempt at using jqGrid in ASP.NET MVC 4 so please forgive the newby question. I appear to have everything working on my end, but when a row is saved during an inline add the grid displays jqg1 instead of the id being returned from the database. The id is there, but for some reason it's not being displayed. When I refresh the grid, the id is then displayed correctly, so it's definitely in the database also. Any ideas would be greatly appreciated. Thanks!!

Grid

    <script type="text/javascript">
    $(document).ready(function () {
        var grid = $('#list'),
            decodeErrorMessage = function (jqXHR, textStatus, errorThrown) {
                var html, errorInfo, i, errorText = textStatus + '\n' + errorThrown;
                if (jqXHR.responseText.charAt(0) === '[') {
                    try {
                        errorInfo = $.parseJSON(jqXHR.responseText);
                        errorText = "";
                        for (i = 0; i < errorInfo.length; i++) {
                            if (errorText.length !== 0) {
                                errorText += "<hr/>";
                            }
                            errorText += errorInfo[i].Source + ": " + errorInfo[i].Message;
                        }
                    }
                    catch (e) { }
                } else {
                    html = /<body.*?>([\s\S]*)<\/body>/i.exec(jqXHR.responseText);
                    if (html !== null && html.length > 1) {
                        errorText = html[1];
                    }
                }
                return errorText;
            };
        grid.jqGrid({
            url: '@Url.Action("DynamicGridData", "Team")',
            datatype: "json",
            mtype: 'POST',
            colNames: ['Id', 'Code', 'Name'],
            colModel: [
                {
                    name: 'TeamId', index: 'TeamId', key: true, width: 50,
                    searchoptions: {
                        sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'],
                        dataInit: function (elem) {
                            $(elem).autocomplete({ source: '@Url.Action("GetIdsAutoComplete", "Team")' });
                        }
                    }
                },
                {
                    name: 'Code', index: 'Code', width: 75, editable: true,
                    searchoptions: {
                        sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'],
                        dataInit: function (elem) {
                            $(elem).autocomplete({ source: '@Url.Action("GetCodesAutoComplete", "Team")' });
                        }
                    }
                },
                {
                    name: 'Name', index: 'Name', width: 200, editable: true,
                    searchoptions: {
                        sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'],
                        dataInit: function (elem) {
                            $(elem).autocomplete({ source: '@Url.Action("GetNamesAutoComplete", "Team")' });
                        }
                    }
                }
            ],
            rowNum: 10,
            rowList: [10, 20, 30],
            pager: '#pager',
            rownumbers: true,
            sortname: 'TeamId',
            sortorder: "desc",
            viewrecords: true,
            altRows: true,
            altclass: 'myAltRowClass',
            width: 700,
            height: 200,
            gridview: true,
            jsonReader: { cell: "" },
            editurl: '@Url.Action("Update", "Team")',
            caption: "Teams",
            loadError: function (jqXHR, textStatus, errorThrown) {
                // remove error div if exist
                $('#' + this.id + '_err').remove();
                // insert div with the error description before the grid
                grid.closest('div.ui-jqgrid').before(
                    '<div id="' + this.id + '_err" style="max-width:' + this.style.width +
                    ';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
                    decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left"/></div>');
            },
            loadComplete: function () {
                // remove error div if exist
                $('#' + this.id + '_err').remove();
            }
        });
        grid.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true, defaultSearch: 'cn' });
        grid.jqGrid('navGrid', '#pager', { add: false, edit: false },
              {}, {}, {}, { multipleSearch: true, overlay: false, width: 480, showQuery: true });
        grid.jqGrid('inlineNav', "#pager");
        grid.jqGrid('navButtonAdd', '#pager',
                    {
                        caption: "", title: "Toggle Searching Toolbar",
                        buttonicon: 'ui-icon-gear',
                        onClickButton: function () { grid[0].toggleToolbar(); }
                    });
    });
</script>

Controller

        // POST: /Team/Update/5

    [HttpPost]
    public ActionResult Update(Team Team, string oper)
    {
        try
        {
            switch (oper)
            {
                case "add":
                    unitOfWork.TeamRepository.Insert(Team);
                    unitOfWork.Save();
                    return RedirectToAction("Search");
                case "edit":
                    if (ModelState.IsValid)
                    {
                        unitOfWork.TeamRepository.Update(Team);
                        unitOfWork.Save();
                        return RedirectToAction("Search");
                    }
                    break;
            }
        }
        catch (DbUpdateConcurrencyException ex)
        {
            var entry = ex.Entries.Single();
            var databaseValues = (Team)entry.GetDatabaseValues().ToObject();
            var clientValues = (Team)entry.Entity;
            if (databaseValues.Code != clientValues.Code)
                ModelState.AddModelError("Code", "Current value: "
                    + databaseValues.Code);
            if (databaseValues.Name != clientValues.Name)
                ModelState.AddModelError("Name", "Current value: "
                    + databaseValues.Name);
            ModelState.AddModelError(string.Empty, "The record you attempted to edit "
                + "was modified by another user after you got the original value. The "
                + "edit operation was canceled and the current values in the database "
                + "have been displayed. If you still want to edit this record, click "
                + "the Save button again. Otherwise click the Back to List hyperlink.");
        }
        catch (DataException)
        {
            //Log the error (add a variable name after DataException)
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
        }
        return View(Team);
    }

Modified the Controller ActionResult to below, but still showing jqg1 in grid until I reload it via the inlineNav button. The database is being updated, but the grid initially shows jqg1 until it is reloaded. Any ideas? Thanks!!

[HttpPost]
    public ActionResult Update(Team Team, string oper)
    {
        try
        {
            if (oper.Equals("add"))
            {
                unitOfWork.TeamRepository.Insert(Team);
                unitOfWork.Save();
            }
            else if (oper.Equals("edit"))
            {
                if (ModelState.IsValid)
                {
                    unitOfWork.TeamRepository.Update(Team);
                    unitOfWork.Save();
                }
            }
        }
        catch (DbUpdateConcurrencyException ex)
        {
            var entry = ex.Entries.Single();
            var databaseValues = (Team)entry.GetDatabaseValues().ToObject();
            var clientValues = (Team)entry.Entity;
            if (databaseValues.Code != clientValues.Code)
                ModelState.AddModelError("Code", "Current value: "
                    + databaseValues.Code);
            if (databaseValues.Name != clientValues.Name)
                ModelState.AddModelError("Name", "Current value: "
                    + databaseValues.Name);
            ModelState.AddModelError(string.Empty, "The record you attempted to edit "
                + "was modified by another user after you got the original value. The "
                + "edit operation was canceled and the current values in the database "
                + "have been displayed. If you still want to edit this record, click "
                + "the Save button again. Otherwise click the Back to List hyperlink.");
        }
        catch (DataException)
        {
            //Log the error (add a variable name after DataException)
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
        }

        var context = new NonTaxContext();
        return Json(new
        {
            total = 1,
            page = 1,
            records = 1,
            rows = (from item in context.Teams
                    where item.TeamId.Equals(Team.TeamId)
                    select item.TeamId).ToList()
        });
    }
Gregg Pulliam
  • 35
  • 1
  • 5
  • Adding some code to your post would help in attempting to locate the issue. Can you post the relevant C#/VB.NET code and the JS for the jqGrid setup? – Cᴏʀʏ Mar 11 '13 at 18:03
  • Sure...sorry about that. – Gregg Pulliam Mar 11 '13 at 18:07
  • Ids in the form `jqg1` means typically that you provided input data in the wrong form for jqGrid. jqGrid could not find any `id` information for the rows of data. You should include JavaScript code which you used to create jqGrid and the test data (JSON, XML or local) which you used to fill the grid. – Oleg Mar 11 '13 at 18:08
  • Thanks Guys! I'll add more as needed. The data is coming in as JSON from the database. – Gregg Pulliam Mar 11 '13 at 18:12
  • Oleg, much of this code was taken from your great Autocomplete example. The main issue may be how to construct the ActionResult for the inline add and edit. My attempt is above, but I may very well be returning the data in the wrong format. – Gregg Pulliam Mar 11 '13 at 18:21
  • @GreggPulliam: [The answer](http://stackoverflow.com/a/7392816/315935) contains the demo project which shows how jQuery UI Autocomplete can be used. – Oleg Mar 12 '13 at 17:00

1 Answers1

1

The problem is that you use inlineNav which work not good enough in case of adding data to the database. So you have to do some additional steps after adding of row inside of aftersavefunc.

grid.jqGrid("inlineNav", "#pager", {
    addParams: {
        addRowParams: {
            aftersavefunc: function (rowId, jqXHR) {
                // here you need place some additional code !!!
                // jqXHR is a superset of the XMLHTTPRequest object
                // typically one need use jqXHR.responseText
                // to access the response from the server
            }
        }
    },
    ... // other options which you need
});

The simplest solution of the problem will be reloading of grid content after adding new row:

aftersavefunc: function () {
    var $this = $(this); // grid
    setTimeout(function () {
        $this.trigger("reloadGrid");
    }, 50);
}

Alternatively you can returns the id of new row from the database. Your current code returns RedirectToAction("Search"); which seems me wrong. If you returns id of new row you can get it as jqXHR.responseText inside of aftersavefunc

aftersavefunc: function function (rowId, jqXHR) {
    var newRowId = jqXHR.responseText; // probably $.parseJSON(jqXHR.responseText)
    $(this).jqGrid("setCell", rowId, "TeamId", newRowId);
    $("#" + $.jgrid.jqID(rowId)).attr("id", newRowId);
}
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks Oleg! What should my Return look like in my code? How do I return the id from my JsonResult in the Controller? – Gregg Pulliam Mar 11 '13 at 23:13
  • @GreggPulliam: I think that you can return just `Content(Team.TeamId)` or `Json(Team.TeamId)`. – Oleg Mar 11 '13 at 23:36
  • Oleg, the aftersavefunction was not called in addParams, but I added it to editParams and it is now called. I decided to return the entire Team object from the controller. It works, but now the added row remains highlighted after being added to the grid. aftersavefunc: function (rowId, jqXHR) { var newRowId = $.parseJSON(jqXHR.responseText); $(this).jqGrid("setCell", rowId, "TeamId", newRowId.TeamId); $("#" + $.jgrid.jqID(rowId)).attr("id", newRowId.TeamId); } – Gregg Pulliam Mar 12 '13 at 13:42
  • @GreggPulliam: I am not sure what is your current problem. Is the problem that the editing row is selected? It's standard behavior of jqGrid. You can open [the official jqGrid demo](http://trirand.com/blog/jqgrid/jqgrid.html) and choose in the tree of demos: "Row Editing (new)" / "Inline Navigator (new)". Do you have the same results in your demo? If you want you can do additional actions inside of `aftersavefunc`. You can use `setSelection` to toggle selection. – Oleg Mar 12 '13 at 17:13