jqGrid: использование нескольких методов для фильтрации данных

Мое требование - показать страницу с несколькими фильтрами для применения к данным сетки.

Предположим, мы говорим о заказах, и заказ имеет следующие атрибуты

public class Order {
    public int OrderID
    public DateTime OrderDate
    public DateTime ShipmentDate
    public int OrderTotal
    public int OrderStatus
}

Внутри объекта jqgrid я показываю все атрибуты кроме OrderStatus

Требуется создать представление, в котором есть

  • jqGrid в левой части
  • панель справа

Внутри правой панели пользователь увидит список флажков, которые представляют все возможные значения OrderStatus, и он хочет выполнить поиск, используя оба метода (например, установив флажок «Отправленные заказы», ​​а затем отфильтруя сетку с суммой, превышающей значение)

Я уже настроил расширенную фильтрацию (multiplesearch:true) внутри объекта jqGrid, и я могу создавать сложные фильтры, объединяющие поля и логические операторы.

Есть идеи, как я могу отправить даже данные с правой панели, когда пользователь нажимает кнопку поиска?

Обновление 1:

Преамбула: Образец Олега отличный, но, к сожалению, не соответствует требованиям моего заказчика :(

@ Олег: Я не понимаю, почему вы так думаете:

Если данные находятся за пределами сетки, вы увидите детали заказа на правой панели только для выбранной строки. Таким образом, у пользователя будет не очень хороший обзор данных.

возможно, мое описание было не таким ясным, но я не собираюсь показывать детали заказа. Чтобы лучше прояснить мои требования, я изменил ваш образец, чтобы показать вам желаемый окончательный интерфейс, как показано на следующем изображении: Пользовательский интерфейс, который хочет клиент

Заказчик хочет фильтровать данные в сетке, используя два метода или оба вместе:

  • Использование возможностей multiplesearch, предоставляемых самой сеткой (спасибо за упоминание обходного пути)
  • Использование предоставленной настраиваемой панели поиска (с флажками справа)

С функциональной точки зрения это требование очень легко выразить: когда пользователь щелкает флажок или выполняет поиск, используя собственный multiplesearch, я должен отправлять значения на сервер, включая также состояние флажков.

Подводя итог, я должен:

  • Добавить состояние флажков, когда публикация делается через нативный multiplesearch
  • Добавить текущее состояние multiplesearch (если есть), когда пользователь устанавливает флажок

Есть ли способ сделать это?


person Lorenzo    schedule 20.10.2010    source источник


Ответы (2)


Я очень хорошо понимаю это требование. В последнем случае я использовал флажки внутри jqGrid. Самым большим преимуществом наличия информации внутри jqGrid является не только возможность простого поиска. Если данные находятся за пределами сетки, вы увидите детали заказа на правой панели только для выбранной строки. Таким образом, у пользователя будет не очень хороший обзор данных.

Чтобы иметь возможность разместить много флажков в таблице без постоянной горизонтальной прокрутки, я повернул заголовки столбцов с флажком, используя технику, описанную в Вертикальный текст внутри заголовков таблиц с использованием библиотеки SVG на основе JavaScript. Это вращение выглядит не идеально в IE, но в другом браузере работает отлично.

Вы можете хранить данные из поля OrderStatus в скрытом столбце и декодировать битовую маску в логическое значение, которое создает флажки либо на стороне клиента, либо на стороне сервера.

Поскольку вы хотите использовать multiplesearch:true, я должен упомянуть об ошибке в jQuery.clone, который следует за ошибка множественного поиска jqGrid во всех версиях браузеров IE. Если вы определите несколько фильтров в качестве одного фильтра поиска, будет использоваться только первый, потому что поле операции всех других фильтров будет читаться как undefined. Жалко, но ошибка также не исправлена ​​в только что опубликованном jQuery 1.4.3. Чтобы иметь возможность использовать multiplesearch:true, вы можете использовать предложение обходного пути от Джихо Хан на форуме trirand.com.

Все вместе вы можете увидеть в демонстрационном примере, который создает сетку

alt text

где вы можете искать по нескольким полям

alt text

Соответствующий код:

var myData = [
    { orderID: "10", orderDate: "2010-09-18", shipmentDate: "2010-09-20", orderStatus: "2" },
    { orderID: "15", orderDate: "2010-09-20", shipmentDate: "2010-09-24", orderStatus: "3" },
    { orderID: "20", orderDate: "2010-10-16", shipmentDate: "2010-10-17", orderStatus: "1" }
];
// decode 'orderStatus' column and add additional boolean data based on the bitmap mask
for (var i=0, l=myData.length; i<l; i++) {
    var myRow = myData[i];
    var orderStatus = parseInt(myRow.orderStatus, 10);
    myRow.airPost = (orderStatus & 2) != 0? "1": "0";
    myRow.heavy = (orderStatus & 1) != 0? "1": "0";
}
var grid = jQuery('#list');
grid.jqGrid({
    data: myData,
    datatype: 'local',
    caption: 'Order Details',
    height: 'auto',
    gridview: true,
    rownumbers: true,
    viewrecords: true,
    pager: '#pager',
    rownumbers: true,
    colNames: ['Order ID', 'Order', 'Shipment', 'Air-Post', 'Heavy', 'RowVersion'],
    colModel: [
        { name: 'orderID', index: 'orderID', key:true, width: 120, sorttype: 'int' },
        { name: 'orderDate', index: 'orderDate', width: 180,
          sorttype: 'date', formatter: 'date' },
        { name: 'shipmentDate', index: 'shipmentDate', width: 180,
          sorttype: 'date', formatter: 'date' },
        { name: 'airPost', width: 21, index: 'airPost', formatter: 'checkbox', align: 'center',
          editoptions: { value: "1:0" }, stype: 'select', searchoptions: { value: "1:Yes;0:No" } },
        { name: 'heavy', width: 21, index: 'heavy', formatter: 'checkbox', align: 'center',
          editoptions: { value: "1:0" }, stype: "select", searchoptions: { value: "1:Yes;0:No" } },
        { name: 'orderStatus', index: 'orderStatus', width: 50, hidden: true }
    ]
}).jqGrid ('navGrid', '#pager', { edit: false, add: false, del: false, refresh: true, view: false },
            {},{},{},{multipleSearch:true})
  .jqGrid ('navButtonAdd', '#pager', { caption: "", buttonicon: "ui-icon-calculator", title: "choose columns",
      onClickButton: function() {
          grid.jqGrid('columnChooser');
      }
  });

где rotateCheckboxColumnHeaders и исправление ошибки в расширенном поиске определено так

// we use workaround from http://www.trirand.com/blog/?page_id=393/bugs/in-multiple-search-second-and-subsequent-ops-are-sent-as-undefined-in-ie6/
// to fix the bug in the jQuery.clone (see http://bugs.jquery.com/ticket/6793 and
// dscussion on the http://api.jquery.com/clone/
jQuery.event.special.click = {
    setup: function() {
        if (jQuery(this).hasClass("ui-search")) {
            jQuery(this).bind("click", jQuery.event.special.click.handler);
        }
        return false;
    },
    teardown: function() {
        jQuery(this).unbind("click", jQuery.event.special.click.handler);
        return false;
    },
    handler: function(event) {
        jQuery(".ui-searchFilter td.ops select").attr("name", "op");
    }
};
var rotateCheckboxColumnHeaders = function (grid, headerHeight) {
    // we use grid as context (if one have more as one table on tnhe page)
    var trHead = jQuery("thead:first tr", grid.hdiv);
    var cm = grid.getGridParam("colModel");
    jQuery("thead:first tr th").height(headerHeight);
    headerHeight = jQuery("thead:first tr th").height();

    for (var iCol = 0; iCol < cm.length; iCol++) {
        var cmi = cm[iCol];
        if (cmi.formatter === 'checkbox') {
            // we must set width of column header div BEFOR adding class "rotate" to
            // prevent text cutting based on the current column width
            var headDiv = jQuery("th:eq(" + iCol + ") div", trHead);
            headDiv.width(headerHeight).addClass("rotate");
            if (!jQuery.browser.msie) {
                if (jQuery.browser.mozilla) {
                    headDiv.css("left", (cmi.width - headerHeight) / 2 + 3).css("bottom", 7);
                }
                else {
                    headDiv.css("left", (cmi.width - headerHeight) / 2);
                }
            }
            else {
                var ieVer = jQuery.browser.version.substr(0, 3);
                // Internet Explorer
                if (ieVer !== "6.0" && ieVer !== "7.0") {
                    jQuery("span", headDiv).css("left", 0);
                    headDiv.css("left", cmi.width / 2 - 4).css("bottom", headerHeight / 2);
                }
                else {
                    headDiv.css("left", 3);
                }
                headDiv.parent().css("zoom",1);
            }
        }
    }
};

Если вы предпочитаете удерживать флажки вне сетки, вы можете выполнить декодирование битовой маски OrderStatus внутри onSelectRow обработчик событий.

ОБНОВЛЕНО: я действительно что-то неправильно понял ваши требования в начале. Взгляните на измененный пример. Теперь это выглядит так: alt text

и это ближе к тому, что вам нужно.

person Oleg    schedule 20.10.2010
comment
ух ты!!! фантастический образец. Спасибо, что потратили время, чтобы собрать все вместе. В любом случае это не соответствует моим требованиям, и, более того, я думаю, что я не объяснил это в лучшем случае. Пожалуйста, ознакомьтесь с моей редакцией сообщения, чтобы получить более подробную информацию. Спасибо! - person Lorenzo; 20.10.2010
comment
@Lorenzo: Я не уверен, что вы видели мою часть UDPATED, которую я написал после того, как вы изменили дату своего вопроса. Это ближе к решению вашей проблемы? - person Oleg; 22.10.2010
comment
Здорово! У меня было время увидеть ваше обновление только сегодня. Это именно то, что я искал. Не могу поставить +5, но точно: спасибо! :) - person Lorenzo; 22.10.2010
comment
@Lorenzo: Я рад это слышать. Я думаю, что этот пример может помочь и другим людям. - person Oleg; 22.10.2010
comment
Я нашел другой способ делать то же самое быстрее. Не могли бы вы взглянуть на него в другом ответе и дать мне несколько советов, если есть какие-либо недостатки в его использовании? Спасибо! - person Lorenzo; 24.10.2010
comment
@Oleg отличный пример! это потрясающе, мне интересно, есть ли какие-то проблемы с попыткой сделать это точно то же самое (программная установка фильтра в jqgrid) только с ОДНИМ фильтром. так что установка свойств searchField, searchOper и searchString ...? - person diegohb; 19.03.2012

В качестве продолжения я включаю сюда еще один метод, который, как я обнаружил, дает тот же результат.

Этот метод предполагает использование параметра postData jqGrid. Внутри метода я определил различные функции, которые проверяют текущий статус флажков и отправляют параметр на сервер, где его можно использовать для фильтрации.

Это образец

postData: {
    pending: function () {
        if ($("#cb_pending").is(':checked')) {
            return true;
        } else {
            return false;
        }
    }
}

Преимущество этого решения по сравнению с описанным Олегом состоит в том, что на стороне сервера можно использовать смешанные логические операторы (И / ИЛИ), в то же время используя раздел фильтров, как в Олег ответить не представляется возможным.

Удачного кодирования!

person Lorenzo    schedule 24.10.2010
comment
Предложить вам то же самое было моей первой идеей. Я предлагаю сделать это многим (см. stackoverflow.com/questions/2928371/), но я быстро обнаружил некоторые проблемы. 1) Вы не написали, какой тип данных ('json', 'local', ...) вы используете 2) Неизвестно, используете ли вы loadonce:frue и, следовательно, поиск на стороне клиента. 3) Самое главное, что могут быть конфликты между фильтром из множественного (расширенного) поиска и флажками из внешнего фильтра. Я должен объяснить проблему более подробно: - person Oleg; 24.10.2010
comment
Поскольку одним из ваших требований является использование multiplesearch средств, вы должны хранить информацию о логическом статусе (например, ожидающий) внутри jqGrid. Вы, конечно, можете изменить диалог множественного поиска внутри afterShowSearch (см., Например, предложение Джастина Этье из заголовка stackoverflow.com/questions/3981874/. Я считаю способ немного сложным, но он будет работать. Самая большая проблема, с которой я сталкиваюсь, конфликты между фильтрами. Допустим, у нас есть, например, скрытый столбец, ожидающий рассмотрения, и мы использовали расширенный поиск, чтобы установить fasle - person Oleg; 24.10.2010
comment
Затем мы проверяем внешний фильтр и проверяем Pending, что соответствует pending: true. Какое значение нужно использовать? По крайней мере, вам нужно сбросить фильтр множественного поиска, как я описал в stackoverflow.com / questions / 3989786 /. Поняв все проблемы, я решаю выбрать способ из своего ответа stackoverflow.com/questions/3981874/. Я синхронизирую внешние фильтры с внутренними фильтрами, и это помогает избежать конфликтов. - person Oleg; 24.10.2010
comment
Если вы используете данные на сервере, вы можете декодировать OrderStatus в 1 и 0 на стороне сервера вместо того, чтобы делать это на стороне клиента в loadCompleted (я тоже подумал об этом и включил возможное решение в закомментированную часть из кода ok-soft-gmbh.com/jqGrid/CheckboxesWithVerticalHeaders.htm). Тем не менее проблему с конфликтами между внешними и внутренними фильтрами необходимо решить. - person Oleg; 24.10.2010