Javascript jqGrid使用JsonString JsonReader实现服务器端排序分页过滤

Javascript jqGrid使用JsonString JsonReader实现服务器端排序分页过滤,javascript,jqgrid,jqgrid-asp.net,Javascript,Jqgrid,Jqgrid Asp.net,我正在ASP.NETMVC3Web应用程序中使用jqGrid(4.3.1) 我有一个独特的情况(至少,我找不到解决方案),因为我的数据是从外部源提供的——在分页片段中——因此我不能使用网格的url属性,但我仍然必须实现服务器端排序、分页和过滤 我的计划是(在解决以下问题后)使用onPaging、onSortCol和beginSearch方法回调web服务并刷新回调中的网格数据 数据以jqGrid可以使用的格式提供(我可以通过jsonReader选项轻松地映射它): 我通过datastr选项传入数

我正在ASP.NETMVC3Web应用程序中使用jqGrid(4.3.1)

我有一个独特的情况(至少,我找不到解决方案),因为我的数据是从外部源提供的——在分页片段中——因此我不能使用网格的url属性,但我仍然必须实现服务器端排序、分页和过滤

我的计划是(在解决以下问题后)使用onPaging、onSortCol和beginSearch方法回调web服务并刷新回调中的网格数据

数据以jqGrid可以使用的格式提供(我可以通过jsonReader选项轻松地映射它):

我通过datastr选项传入数据,并将数据类型设置为“jsonstring”

loadonce设置为false(我已经尝试了两种方法),我的rowNum设置为10

当我第一次调用时,一个包含900条记录的数据集返回,网格显示前10条记录,但寻呼机忽略了“总计”和“记录”,认为我只有一页数据

未忽略根数据(显示10条记录)和用户数据(即页脚正确呈现)。因此,网格选择性地忽略了datastr中的“总计”和“记录”数据

我的问题是-使用datatype:jsonstring和datastr(并向网格提供json而不是使用url)是否会阻止利用服务器端分页/排序/过滤的能力

如果是这样的话,有没有办法实现我的目标

请注意,如果我返回整个900计数记录集,并将loadonce设置为true,则一切正常,尽管是客户端的

我的整个jqGrid,供参考:

g.claims.LoadGrid = function (url, pagerDiv, grid, caption, drillData) {
    jQuery(grid).jqGrid({
        url: url,
        datastr: drillData != null ? drillData : g.claims.gridData,
        datatype: 'jsonstring',
        mtype: 'POST',
        ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
        serializeGridData: function (postData) {
            if (postData.filters === undefined) postData.filters = null;
            postData.quick = $("#quickSearchText").val();
            return JSON.stringify(postData);
        },
jsonReader: {
    repeatitems: false,
    root: "Rows",
    page: "Page",
    total: "TotalPages",
    records: "RecordCount",
    userdata: "FooterTotals",
    id: "ClaimId"
},
        colNames: ['ClaimId', 'Claim Reference', 'Status', 'Handler', 'Create Date', 'Division', 'Line Of Business', 'Policy Reference', 'Incurred Amount', 'Paid Amount'],
        colModel: [
                { name: 'ClaimId', index: 'ClaimId', width: 90, sorttype: 'integer', align: 'right', searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'ClaimRef', index: 'ClaimRef', width: 120, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'Status', index: 'Status', width: 100, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'Handler', index: 'Handler', width: 140, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'CreateDateDisplay', index: 'CreateDateDisplay', width: 90, align: 'center', sorttype: 'date', formatter: 'date', formatoptions: { srcformat: 'M-d-Y', newformat: 'd-M-Y' }, editable: true, datefmt: 'd-M-Y',
                editoptions: { dataInit: g.claims.initDateEdit },
                searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'], dataInit: g.claims.initDateSearch }
            },
            { name: 'Division', index: 'Division', width: 90, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'LineOfBusiness', index: 'LineOfBusiness', width: 120, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'PolicyRef', index: 'PolicyRef', width: 120, searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'IncurredAmount', index: 'IncurredAmount', width: 120, sorttype: 'currency', align: 'right', searchoptions: { sopt: ['cn', 'eq', 'ne']} },
            { name: 'PaidAmount', index: 'PaidAmount', width: 120, sorttype: 'currency', align: 'right', searchoptions: { sopt: ['cn', 'eq', 'ne']} }

            ],
        rowNum: 10,
        rowList: [10, 20, 30],
        pager: pagerDiv,
        loadonce: false,
        sortname: 'ClaimId',
        viewrecords: true,
        sortorder: "desc",
        height: 250,
        ignoreCase: true,
        loadui: 'disable',
        autowidth: true,
        caption: caption,
        sortable: true,
        shrinkToFit: false,
        footerrow: true,
        userDataOnFooter: true,
        gridview: false,
        loadComplete: function () {
            var filters, quick, i, l, rules, rule, iCol, $this = $(this);
            if (this.p.search === true) {
                filters = $.parseJSON(this.p.postData.filters);
                if (filters !== null && typeof filters.rules !== 'undefined' && filters.rules.length > 0) {
                    rules = filters.rules;
                    l = rules.length;
                    for (i = 0; i < l; i++) {
                        rule = rules[i];
                        iCol = g.GetColumnIndexByName($this, rule.field);
                        if (iCol >= 0) {
                            $('>tbody>tr.jqgrow>td:nth-child(' + (iCol + 1) + ')', this).highlight(rule.data);
                        }
                    }
                }
            }
            quick = $("#quickSearchText").val();
            if (quick !== null) {
                var colCount = g.GetColumnCount($this);
                for (i = 0; i < colCount; i += 1) {
                    $('>tbody>tr.jqgrow>td:nth-child(' + (i + 1) + ')', this).highlight(quick);
                }
            }
            return;
        },
        onSelectRow: function (id) {
            var ret = jQuery(grid).jqGrid('getRowData', id);
            alert(ret.ClaimRef);
            //_currentRequestId = ret.RequestId;
            //ShowRequest();
        },
        loadError: function (xhr, textStatus, errorThrown) {
            var errorMsg = xhr.responseText;
            var msg = "Some errors occurred during processing:";
            msg += '\n\n' + textStatus + '\n\n' + errorMsg;
            g.trackError(msg, document.URL, 0);
        }

    });
    jQuery(grid).jqGrid('navGrid', pagerDiv, { refresh: false, edit: false, add: false, del: false, search: false });
    //jQuery(grid).jqGrid('setFrozenColumns');
    jQuery(grid).jqGrid(
        'navButtonAdd',
        pagerDiv,
        {
            caption: "",
            buttonicon: "ui-icon-newwin",
            title: "choose columns",
            onClickButton: function () {
                $(this).jqGrid('columnChooser', {
                    done: function () {
                        $(grid).trigger("resize");
                    }
                });
            }
        }
    );

    jQuery(grid).jqGrid(
        'navButtonAdd',
        pagerDiv,
        {
            caption: "",
            buttonicon: "ui-icon-refresh",
            title: $.jgrid.nav.refreshtitle,
            onClickButton: function () {
                $(this).jqGrid('setGridParam', { datatype: 'json' });
                $(this).trigger('reloadGrid', [{ page: 1}]);
            }
        }
    );

    jQuery(grid).jqGrid('filterToolbar', {
        stringResult: true,
        searchOnEnter: false,
        defaultSearch: 'cn',
        beforeSearch: function () {
            var postedData = $(this).jqGrid('getGridParam', 'postData');
            g.claims.FilterPageSort(postedData);
            return false;
        }
    });
    jQuery(grid).fluidGrid({ example: "#gridParent", offset: 0 });
};
上述代码中提到的图表类:

public class Chart
{
    public List<ColumnSeries> Series { get; set; }
    public List<string> Categories { get; set; }
}

public class ColumnSeries
{
    public string Name { get; set; }
    public List<object> Values { get; set; }
}

您可以直接在jqGrid中加载数据。为此,只需将
url
参数设置为
GetLagChart
操作,并稍微更改
jsonReader

jsonReader: {
    repeatitems: false,
    root: "GridData.Rows",
    page: "GridData.Page",
    total: "GridData.TotalPages",
    records: "GridData.RecordCount",
    userdata: "GridData.FooterTotals",
    id: "ClaimId"
}
loadComplete
中,您可以完全访问服务器返回的数据,因此可以使用服务器响应的
LagChart
部分来填充或更新图表

使用关于以下内容的
loadComplete

loadComplete: function (data) {
    if (typeof data.LagChart !== "undefined") {
        var chartInfo = data.LagChart
        alert ("Categories count: " + data.LagChart.Categories.length +
               "\nSeries count: " + data.LagChart.Series.length +
               "\n\nWe can fill/update the Chart");
    }
}

因此,实现中最重要的部分将是服务器方法
GetResults
,它提供网格数据页面。您可以使用
过滤器
参数扩展该方法。关于更多的实现细节,我建议您阅读或阅读包含更多最新和扩展代码的版本。

我不明白您为什么不能直接从“外部源”加载数据。你写道你称之为“网络服务”。你会单独打Ajax电话吗?您使用JSON还是JSONP调用?web服务的接口是什么?因为你写了关于ASP.NETMVC3Web应用程序的文章,所以我对所有事件都不太了解。jqGrid允许非常大的灵活性。因此,如果您提供有关web服务接口的更多详细信息,或者发布您当前用于调用它的代码,我将尝试向您展示如何在jqGrid中集成该调用。@Oleg-感谢您的快速响应。最初的web服务调用将带回网格数据以及与视图模型中页面其余部分相关的许多其他数据元素。如果我使用url,我将无法访问此数据。至少我不知道。jqGrid是更大页面的一部分,前面填充了前10条记录。这就是为什么我希望我可以使用datastr/jsonstring将json(通过单独的ajax调用传递给我)传递到网格,然后调用web服务(同样,我不控制)对数据进行分页/过滤/排序,如果需要,您甚至可以在jqGrid处理它之前对其进行修改。从服务器获取数据后,还可以填充或刷新外部字段。如果您只是描述外部数据字段,请发布用于从服务器获取数据的Ajax调用,并包括JSON响应示例(一行网格数据和一个外部字段就足够了),我可以向您展示如何做到这一点。@Oleg-我已经添加了您评论中要求的详细信息。非常感谢你抽出时间帮忙。谢谢。我将按照您的建议从loadComplete中的数据对象中解析所需内容。@kmk:不客气!不要忘记将
gridview
也设置为
true
。电网运行迅速,没有缺点。只有使用多行数据才能真正看到性能优势。我向您发送了一封有关上述数据的电子邮件。有机会时请看一看(与SO无关)。谢谢你的帮助。
public class GridData<T>
{
    public int TotalPages { get; set; }
    public int Page { get; set; }
    public int RecordCount { get; set; }
    public List<T> Rows { get; set; }
    public object FooterTotals { get; set; }
}
{
  "GridData": {
    "TotalPages": 92,
    "Page": 1,
    "RecordCount": 911,
    "Rows": [
      {
        "ClaimId": 229731,
        "ClaimRef": "XXX111345",
        "ClaimTitle": "title 1",
        "Status": "Claim - Finalised",
        "IncurredAmount": 0.00,
        "PaidAmount": 0.00,
        "Handler": "Person One",
        "Handler1": "Person One",
        "Handler2": "Person One",
        "Handler3": "Person One",
        "Division": "Person One",
        "Branch": null,
        "LineOfBusiness": "Wholesale Excess",
        "PolicyRef": "SFSF9090888",
        "CreateDateDisplay": "03-30-2012",
        "DateOfAdvice": "2009-06-01T00:00:00",
        "DateOfLoss": "2007-07-08T00:00:00",
        "LossPeriod": 200707,
        "DateOfFirstReserve": "2009-06-03T00:00:00",
        "AdviceLag": 695,
        "ReserveLag": 3
      },
      {
        "ClaimId": 229933,
        "ClaimRef": "EXC123488",
        "ClaimTitle": "Title 2",
        "Status": "Claim - Finalised",
        "IncurredAmount": 0.00,
        "PaidAmount": 0.00,
        "Handler": "Person Two",
        "Handler1": "Person Two",
        "Handler2": "Person Two",
        "Handler3": "Person Two",
        "Division": "Excess",
        "Branch": null,
        "LineOfBusiness": "Wholesale Excess",
        "PolicyRef": "NY676767777",
        "CreateDateDisplay": "03-30-2012",
        "DateOfAdvice": "2009-06-02T00:00:00",
        "DateOfLoss": "2006-01-01T00:00:00",
        "LossPeriod": 200601,
        "DateOfFirstReserve": "2009-06-18T00:00:00",
        "AdviceLag": 1249,
        "ReserveLag": 17
      },
      ...
    ],
    "FooterTotals": {
      "ClaimId": "Totals",
      "IncurredAmount": -27910474.80,
      "PaidAmount": -27910474.80
    }
  },
  "LagChart": {
    "Series": [
      {
        "Name": "Average Advice Lag",
        "Values": [
          1499,
          1048,
          897,
          2354,
          1450,
          444,
          334,
          816,
          508,
          108,
          256,
          109
        ]
      },
      {
        "Name": "Average Reserve Lag",
        "Values": [
          44,
          131,
          23,
          76,
          67,
          18,
          122,
          45,
          29,
          15,
          3,
          14
        ]
      }
    ],
    "Categories": [
      "Jan 2011",
      "Feb 2011",
      "Mar 2011",
      "Apr 2011",
      "May 2011",
      "Jun 2011",
      "Jul 2011",
      "Aug 2011",
      "Sep 2011",
      "Oct 2011",
      "Nov 2011",
      "Dec 2011"
    ]
  }
}
jsonReader: {
    repeatitems: false,
    root: "GridData.Rows",
    page: "GridData.Page",
    total: "GridData.TotalPages",
    records: "GridData.RecordCount",
    userdata: "GridData.FooterTotals",
    id: "ClaimId"
}
loadComplete: function (data) {
    if (typeof data.LagChart !== "undefined") {
        var chartInfo = data.LagChart
        alert ("Categories count: " + data.LagChart.Categories.length +
               "\nSeries count: " + data.LagChart.Series.length +
               "\n\nWe can fill/update the Chart");
    }
}