【问题标题】:jqGrid Using JsonString-JsonReader Implementing Server-Side Sorting Paging FilteringjqGrid使用JsonString-JsonReader实现服务端排序分页过滤
【发布时间】:2012-04-13 11:26:09
【问题描述】:

我在 ASP.NET MVC 3 Web 应用程序中使用 jqGrid (4.3.1)。

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

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

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

jsonReader: {
    repeatitems: false,
    root: "Rows",
    page: "Page",
    total: "TotalPages",
    records: "RecordCount",
    userdata: "FooterTotals",
    id: "ClaimId"
},

我通过 datastr 选项传入数据并将数据类型设置为 'jsonstring'。

loadonce 设置为 false(我已经尝试过两种方式),并且我的 rowNum 设置为 10。

当我进行初始调用时,包含约 900 条记录的数据集返回,并且网格显示前 10 条记录,但寻呼机忽略了“总计”和“记录”,并认为我只有 1 页数据

根数据未被忽略(它显示 10 条记录)并且用户数据未被忽略(即页脚正确呈现)。因此网格会选择性地忽略 datastr 中的“total”和“records”数据。

我的问题是 - 使用 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 });
};

更新(有关 Oleg 的更多信息):

ajax 调用控制器方法(该方法具有引用下面描述的类的 cmets)。此方法遵循 jqGrid JSON 序列化的 postData 结构(带有一些额外参数):

    [HttpPost]
    public ActionResult GetLagChart(int page, int rows, string sidx, string sord, bool _search, string filters, string quick)
    {
        var claims = WarehouseDataProvider.Instance.GetClaim(quick);

        //will eventually be passed in as jqGrid filters - not yet implemented
        var startPeriod = 201101;
        var endPeriod = 201112;

        //the return of this method is of type Chart - see below
        var lag = WarehouseDataProvider.Instance.GetLagChart(claims, startPeriod, endPeriod);


        var viewModel = new LagChartViewModel
                            {
                                LagChart = lag,
                                GridData = GetResults(claims, page, rows, sidx, sord)
                            };

        return this.JsonNet(viewModel);
    }

上面代码中提到的Chart类:

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 GridData类:

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; }
}

将 Json 示例发布到 Web 服务(支持 HttpPost 的控制器):

{"page":1,"rows":10,"sidx":"ClaimId","sord":"asc","_search":false,"filters":null,"quick":"exc "}

响应 Ajax:

{
  "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"
    ]
  }
}

【问题讨论】:

  • 我不明白为什么不能直接从“外部来源”加载数据。您写道,您称之为“网络服务”。您是否进行单独的 Ajax 调用?你使用 JSON 还是 JSONP 调用? Web服务的接口是什么?因为您写了关于 ASP.NET MVC 3 Web 应用程序的文章,所以我对所有事件的了解都更少。 jqGrid 提供了很大的灵活性。因此,如果您包含有关 Web 服务接口的更多详细信息或发布您当前用来调用它的代码,我会尝试向您展示如何将调用集成到 jqGrid 中。
  • @Oleg - 感谢您的快速回复。最初的 Web 服务调用会带回网格数据以及与视图模型中页面其余部分相关的许多其他数据元素。如果我使用 url,我将无法访问这些数据。至少我知道没有办法。 jqGrid 是一个较大页面的一部分,前 10 条记录填充在前面。这就是为什么我希望我可以使用 datastr/jsonstring 将 json(通过单独的 ajax 调用传递给我)传递给网格,然后调用 Web 服务(同样,我无法控制)进行分页/过滤/排序数据。
  • 您确实可以获得对服务器响应的完全访问权限,如果需要,您甚至可以在 jqGrid 处理之前对其进行修改。您还可以在从服务器获取数据后填充或刷新外部字段。如果您只是描述外部数据字段,请发布用于从服务器获取数据的 Ajax 调用并包含 JSON 响应的示例(一行网格数据和一个外部字段就足够了)我可以展示您如何这样做。
  • @Oleg - 我已经添加了您评论中要求的详细信息。非常感谢您抽出宝贵时间提供帮助。

标签: javascript jqgrid jqgrid-asp.net


【解决方案1】:

您可以直接在 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 部分来填充或更新图表。

The demo 使用大约以下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。您可以使用filters 参数扩展该方法。有关更多实现细节,我建议您阅读the answerthis one,其中包含更新和扩展的代码。

【讨论】:

  • 谢谢。我将按照您的建议从 loadComplete 中的数据对象解析我需要的内容。
  • @kmk:不客气!不要忘记也将gridview 设置为true。网格将很快工作而没有缺点。只有多行数据才能真正看到性能优势。
  • 我向您发送了一封关于上述数据的电子邮件。有机会时请看一下(与SO无关)。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 2019-04-30
  • 2014-10-01
  • 2013-07-21
相关资源
最近更新 更多