jqGrid с использованием JsonString-JsonReader, реализующего фильтрацию подкачки сортировки на стороне сервера

Я использую jqGrid (4.3.1) в веб-приложении ASP.NET MVC 3.

У меня уникальная ситуация (по крайней мере, та, для которой я не могу найти решение), поскольку мне предоставляются мои данные из внешнего источника - в виде фрагментов с разбивкой на страницы, поэтому я не могу использовать свойство url сетки, но я по-прежнему необходимо реализовать сортировку, разбиение по страницам и фильтрацию на стороне сервера.

Мой план (как только я разрешаю нижеследующее) использовать методы onPaging, onSortCol и beginSearch для обратного вызова веб-службы и обновления данных сетки в обратном вызове.

Данные предоставляются в формате, пригодном для использования 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.

Мой вопрос: запрещает ли использование типа данных: 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 });
};

ОБНОВЛЕНИЕ (подробнее для Олега):

Ajax вызывает метод контроллера (в котором есть комментарии, которые ссылаются на классы, описанные ниже). Этот метод придерживается структуры postData jqGrid, сериализованной JSON (с несколькими дополнительными параметрами):

    [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 в веб-службу (контроллер с поддержкой 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"
    ]
  }
}

person kmk    schedule 29.03.2012    source источник
comment
Я не понимаю, почему нельзя загружать данные напрямую из внешнего источника. Вы написали, что звоните в веб-сервис. Вы делаете отдельный вызов Ajax? Вы используете вызов JSON или JSONP? Каков интерфейс веб-сервиса? Из-за того, что вы писали о веб-приложении ASP.NET MVC 3, я меньше понимаю все происходящее. jqGrid обеспечивает большую гибкость. Поэтому, если вы включите более подробную информацию об интерфейсе веб-службы или опубликуете код, который вы используете в настоящее время для его вызова, я бы попытался показать вам, как интегрировать вызов в jqGrid.   -  person Oleg    schedule 29.03.2012
comment
@Oleg - Спасибо за быстрый ответ. Исходный вызов веб-службы возвращает данные сетки вместе со многими другими элементами данных, относящимися к остальной части страницы в модели представления. Если я использую URL-адрес, у меня нет возможности получить доступ к этим данным. По крайней мере, я не знаю. jqGrid - это одна часть большей страницы, с первыми 10 записями, заполненными впереди. Вот почему я надеялся, что смогу передать json (который передается мне через отдельный вызов ajax) в сетку с помощью datastr / jsonstring, а затем вызвать веб-службу (опять же, которую я не контролирую) для подкачки / фильтрации / сортировка данных.   -  person kmk    schedule 30.03.2012
comment
Вы можете получить полный доступ к ответу сервера, вы даже можете изменить его при необходимости, прежде чем он будет обработан jqGrid. Вы также можете заполнить или обновить внешние поля после получения данных с сервера. Если вы просто опишете поле внешних данных, опубликуете вызов Ajax, который вы используете для получения данных с сервера, и включите пример ответа JSON (будет достаточно данных сетки одной строки и одного внешнего поля), я мог бы показать, как вы можете сделай это.   -  person Oleg    schedule 30.03.2012
comment
@Oleg - Я добавил деталь, запрошенную из вашего комментария. Большое спасибо за то, что нашли время помочь.   -  person kmk    schedule 30.03.2012


Ответы (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 часть ответа сервера для заполнения или обновления диаграммы.

В демонстрации используются примерно следующие 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. Для получения дополнительных сведений о реализации я рекомендую вам прочитать ответ или этот, который содержит более свежий и расширенный код.

person Oleg    schedule 30.03.2012
comment
благодаря. Я проанализирую то, что мне нужно, из объекта данных в loadComplete, как вы предлагаете. - person kmk; 30.03.2012
comment
@kmk: Пожалуйста! Не забудьте также установить gridview на true. Сетка просто будет работать быстро без недостатков. Действительно, можно увидеть преимущества в производительности только при большом количестве строк данных. - person Oleg; 30.03.2012
comment
Я отправил вам электронное письмо с указанными выше данными. Пожалуйста, взгляните, когда у вас будет возможность (не имеющая отношения к SO). Спасибо за вашу помощь. - person kmk; 30.03.2012