Внешняя фильтрация free-jqGrid, используемая с событием грида beforeRequest() или onPaging()

Использование бесплатной версии jqGrid (версия 4.15.6) для отображения самой базовой информации о счетах-фактурах (т. е.: дата создания, срок оплаты, клиент, общая сумма, статус). В сетке счетов-фактур отображается только несколько соответствующих столбцов, потому что нет необходимости показывать больше. На самом деле существует множество других полей, связанных со счетом-фактурой, которые не отображаются. Я хотел бы предложить конечным пользователям возможность фильтровать сетку на основе множества других параметров, которые просто не являются частью содержимого сетки.

Я знаю, что jqGrid предлагает встроенный поиск, и вы можете легко просто добавить скрытые столбцы со всеми данными, но я чувствую, что это не очень хорошо для нас — счета-фактуры содержат много данных — данные, которые не обязательно присутствуют только в таблица базы данных счетов-фактур. Мы хотим, чтобы сетка предоставляла множество других параметров фильтрации помимо базовых данных счета, но мы НЕ хотим использовать встроенные параметры фильтра. Вместо этого я хотел бы использовать отдельную HTML-таблицу с кучей полей поиска, которые наш код на стороне сервера знал бы, как вернуть). Когда кто-то решает вызвать внешний фильтр, мы хотим, чтобы сетка загружала все счета, соответствующие этому комбинированному фильтру. И если кто-то решит перемещаться с помощью кнопок пейджинга сетки, мы хотим, чтобы сетка продолжала использовать исходные параметры внешней фильтрации.

Надеюсь, это имеет смысл. Может быть, я просто слишком много думаю об этом, но я совершенно уверен, что сетка предназначена для использования встроенных инструментов фильтрации/поиска/диалога, и я так и не нашел, чтобы переопределить это поведение. На самом деле я использую более старый jqGrid, но это связано с использованием jQuery для полной ЗАМЕНЫ пейджера по умолчанию с пользовательским HTML и обработкой событий. Я никогда не мог понять это со старым jqGrid, поэтому решил написать его сам. Но этот код далеко не оптимален, и даже я знаю, что он подвергается серьезной критике. После обновления до 4.15.6 я хочу сделать это наилучшим образом и сохранить логику и практичность.

Я попытался использовать события beforeRequest() и onPaging() для изменения параметра 'url', думая, что если я изменю URL-адрес, я смогу изменить GET, чтобы включить все наши настраиваемые поля фильтрации. Кажется, что это не работает, так как URL-адрес НИКОГДА не меняется с первоначально определенного значения. Журнал консоли показывает запуск событий, но не изменяет URL-адрес. Кроме того, сетка ВСЕГДА передает на сервер свое собственное поле страницы, поле _search и т. д., поэтому сервер НИКОГДА не видит запрос фильтра.

Как определить свою собственную фильтрацию в сочетании с загрузчиком страниц и при этом использовать преимущества встроенных событий страниц? Что мне не хватает?

**** УДАЛЕННЫЙ КОД, КОТОРЫЙ БЫЛ ДОБАВЛЕН К ВОПРОСУ, НЕ ОТНОСЯЩЕМУСЯ К ИСХОДНОМУ ВОПРОСУ *********


person Chance    schedule 23.08.2018    source источник
comment
В Guriddo jqGrid есть недокументированный параметр columns в методе searchGrid. Этот параметр, когда он определен, перезаписывает colModel, позволяя определить вашу собственную диалоговую таблицу поиска и синхронизировать пейджинг и другие действия. Я не мог сказать вам, доступен ли он и в free-jqGrid.   -  person Tony Tomov    schedule 24.08.2018


Ответы (2)


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

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

  • фильтрация на стороне сервера
  • фильтрация на стороне клиента

Можно дополнительно использовать смесь от обеих фильтров. Например, можно загрузить с сервера все счета на основе некоторых фиксированных фильтров (все счета конкретного пользователя или все счета одной организации, все счета за последний месяц), а затем использовать параметры loadonce: true, forceClientSorting: true для сортировки и фильтрации возвращаемых данных по клиентская сторона. Пользователь может дополнительно фильтровать подмножество данных локально, используя панель инструментов фильтра диалогового окна поиска.

В последние годы производительность клиентской стороны значительно улучшилась, и загрузка относительно больших данных JSON с сервера стала выполняться очень быстро. Из-за этого фильтрация на стороне клиента строго рекомендуется. Чтобы лучше понять производительность локальной сортировки, фильтрации и разбиения по страницам, я рекомендую вам попробовать функциональность на демонстрация. Вы увидите, что время локальной фильтрации сетки с 5000 строками и 13 столбцами лучше, поскольку вы можете ожидать, в основном, от кругового пути к серверу и обработки фильтрации на стороне сервера в какой-то очень хорошо организованной базе данных. По этой причине я рекомендую рассмотреть возможность использования сортировки на стороне клиента (или loadonce: true, forceClientSorting: true параметров), насколько это возможно.

Если вам нужно фильтровать данные на сервере, вам нужно просто отправлять дополнительные параметры на сервер при каждом запросе. Это можно сделать, включив дополнительные параметры в postData. Дополнительные сведения см. в старом ответе. В качестве альтернативы можно использовать serializeGridData для расширения/изменения данных, которые будут установлены на сервере.

После загрузки данных с сервера их можно отсортировать и отфильтровать локально, до первой страницы данных, которая будет отображаться в сетке. Для принудительной локальной фильтрации достаточно добавить forceClientSorting: true дополнительно к известному параметру loadonce: true. Это принудительно применяет локальную логику к данным, возвращаемым с сервера. Таким образом, можно использовать postData.filters, search: true для принудительной дополнительной локальной фильтрации и параметры sortname и sortorder для принудительной локальной сортировки.

Еще одно важное замечание об использовании скрытых столбцов. Каждый скрытый столбец заставит создавать элементы DOM, которые представляют ненужные элементы <td>. Чем больше элементов DOM вы разместите на странице, тем медленнее будет страница. Если будут использоваться локальные данные (или если будут использоваться loadonce: true), то jqGrid будет хранить данные, связанные с каждой строкой, дважды: один раз как объект JavaScript и один раз как ячейки в сетке (элементы <td>). Бесплатный jqGrid позволяет использовать «дополнительные свойства» вместо скрытых столбцов. В этом случае никакие данные не будут помещены в DOM сетки, но данные будут храниться в объектах JavaScript и можно сортировать или фильтровать по дополнительным свойствам так же, как и в других столбцах. Проще всего можно удалить все скрытые столбцы и добавить параметр additionalProperties, который должен быть массивом строк с названием дополнительных свойств. Вместо строк элементы additionalProperties могут быть объектами той же структуры, что и colModel. Например, additionalProperties: [{ name: "taskId", sorttype: "integer"}, "isFinal"]. См. демонстрацию в качестве примера. Входные данные сетки можно увидеть здесь. Другая демонстрация показывает, что диалоговое окно поиска содержит дополнительные свойства в дополнение к jqGrid столбец. Комментированная часть columns из searching показывает более продвинутый способ указания списка и порядка столбцов и дополнительных свойств, отображаемых в диалоговом окне поиска.

person Oleg    schedule 24.08.2018
comment
Я смог объединить несколько других ваших демонстраций из комментариев, размещенных на похожие вопросы. У меня v4.15.6 прекрасно работает с настраиваемой внешней формой фильтрации и поддерживает встроенную подкачку. Но, поскольку счета-фактуры могут содержать так много данных, лучше всего позволить серверу предоставить ядро, которое составляет основное содержимое сетки, а затем использовать клиентскую сторону для быстрой фильтрации видимых столбцов, как вы предлагаете. Тем не менее, я хочу контролировать загрузку сетки на основе одной из двух вещей: 1) статус или клиент передаются PHP-скрипту в качестве параметров URL-адреса при загрузке первой страницы или.... - person Chance; 24.08.2018
comment
2) все внешние фильтруемые параметры передаются через postData и перезагрузку сетки при стандартном пейджинге. Итак, если сетка загружается из-за обычного пейджинга, то примените существующие фильтры postData (если они есть). Но если сетка загружается при начальной загрузке страницы, я хочу, чтобы сетка загружала только счета-фактуры в статусе «Неоплаченный» и, возможно, назначенные конкретному клиенту, а при подкачке сетка должна сохранять эти два параметра в качестве фильтров. Можете ли вы предоставить пример, показывающий, как настроить фильтрацию jqGrid при начальной загрузке страницы? - person Chance; 24.08.2018
comment
@Chance: я не уверен, что понимаю, что ты имеешь в виду. В общем, если вы хотите использовать чистую фильтрацию на стороне сервера, вам придется реализовать всю необходимую логику самостоятельно. Например, вы можете использовать некоторый postData для первоначальной загрузки, а затем изменить его. Вы можете использовать var p = $("#gridid").jqGrid("getGridParam") для получения всех параметров jqGrid, вы можете изменить/заменить p.postData в любое время позже, просто добавив или удалив некоторые свойства/методы объекта p.postData. Кроме того, вы можете использовать localStorage для сохранения/восстановления некоторых исходных фильтров для следующего посещения той же страницы. - person Oleg; 24.08.2018
comment
@Chance: см. здесь или здесь примеры использования localStorage вместе с jqGrid. - person Oleg; 24.08.2018
comment
У меня есть фильтрация на сервере, и она работает отлично. Я понимаю, что вы имеете в виду об изменении postData после начальной загрузки. Но чего я до сих пор не могу сделать, так это заставить сетку представлять данные на сервер таким образом, чтобы я знал, что сетка делает этот первый вызов на сервер. Я пробовал все: от добавления параметров в физическую адресную строку в браузере, передачи параметров по умолчанию в URL или postData в параметрах jqGrid для определения параметров по умолчанию. Я не могу заставить сетку фильтровать при загрузке первой страницы. Я не собираюсь использовать localStorage - я просто хочу определить фильтрацию по умолчанию..... - person Chance; 24.08.2018
comment
так что, когда сетка вызывает скрипт, определенный параметром url, сетка также передает два параметра фильтрации по умолчанию и устанавливает для _search значение true, чтобы код на стороне сервера знал, что нужно фильтровать, и возвращал данные json. - person Chance; 24.08.2018
comment
Очень неприятно, потому что при загрузке страницы, где фильтр не установлен, в форме фильтра установлены правильные значения фильтра для статуса/клиента, но сетка загружает все счета. На данный момент сетка уже запросила у сервера записи. Как только я публикую фильтр ПОСЛЕ начальной загрузки страницы, в сетке появляются нужные записи...... - person Chance; 24.08.2018
comment
Я думал об установке функции тайм-аута и загрузке фильтра по умолчанию таким образом, но это ДВЕ загрузки сетки. В этом случае jqGrid дважды вызывает URL-адрес — сначала при загрузке страницы, а затем по тайм-ауту для установки фильтра по умолчанию. Я хотел бы, чтобы только этот первый вызов сервера содержал фильтрацию по умолчанию, представленную сеткой. Я попробовал данные: '{$json_encoded_initial_data}', но это ничего не дало. Сетка по-прежнему обращалась к параметру URL для записей, полностью игнорируя данные. - person Chance; 24.08.2018
comment
Олег, я отредактировал исходный вопрос и разместил часть кода. На данный момент я чувствую, что вопрос больше не по теме. И только размещение некоторых кодов кажется еще более запутанным. Просто нет возможности все опубликовать. Надеюсь, вы видите из кода, что я пытаюсь сделать. - person Chance; 24.08.2018
comment
@Chance: я вижу, что ваш код на стороне сервера фильтрует, если установлены _search=true и filters. Вы несколько раз пишете, что хотите использовать начальный фильтр, но ваш код не устанавливает никакого исходного фильтра. Для установки начального фильтра нужно просто добавить параметр search: true jqGrid (он будет отправлен на сервер как _search=true) и установить параметр postData.filters. - person Oleg; 25.08.2018
comment
@Chance: я включил в свой ответ ссылки на некоторые демонстрации. Вы можете изучить код демо, например, и используйте инструменты разработчика (вкладка «Сеть»), чтобы увидеть, что _search: true и filters: {"groupOp":"AND","groups":[],"rules":[{"field":"isFinal","op":"eq","data":"1"}]} отправляются на сервер во время первоначального запроса к серверу для загрузки данных. Разве это не то, что вы хотите? - person Oleg; 25.08.2018
comment
Давайте продолжим обсуждение в чате. - person Chance; 25.08.2018
comment
Олег, Как упоминалось в нескольких комментариях, можете ли вы показать мне пример, где фильтр по умолчанию устанавливается при начальной загрузке страницы? Мне нужно решение, которое позволяет мне запрашивать фильтр по умолчанию при начальной загрузке страницы, а также позволяет разбивку на страницы сетки сохранять фильтр по умолчанию на месте до тех пор, пока конечным пользователем не будет установлен новый фильтр. Я не хочу сохраняться в разных сеансах, поэтому локального хранилища слишком много. Просто хочу, чтобы сетка изначально была загружена неоплаченными счетами. Кажется, это должно быть просто, но я терплю неудачу. Можете ли вы предоставить очень общий пример, который фокусируется только на фильтре загрузки по умолчанию? - person Chance; 25.08.2018
comment
@Chance: Повторяю: вам нужно сделать 2 вещи: 1) добавить опцию postData.filters с начальным фильтром, который вы хотите применить 2) добавить search: true, чтобы включить фильтр. Вы пробовали это? - person Oleg; 25.08.2018
comment
Олег, извините, что не совсем понятно. Как мы можем общаться, если я не ограничен в длине текста? Я пытался публиковать много вещей, и этот форум продолжает говорить, что я превысил лимит символов. Мне нравится думать, что я довольно умен и пробовал все, что вы рекомендуете. Я попытался установить начальные postData.filters в сетке def. Это привело к бесконечным вызовам AJAX к серверу — сетка никогда не заканчивала загрузку. На данный момент никакие счета-фактуры не должны загружаться сначала (предложение php IF при тестировании параметра $_search по-прежнему равно true при начальной загрузке страницы, даже если оно не установлено!). - person Chance; 25.08.2018
comment
@Chance: Какой mtype вы используете: GET или POST? Если список параметров может быть длинным, вам следует использовать HTTP-метод POST вместо GET. Не имеет ограничений по длине параметров - person Oleg; 25.08.2018
comment
Олег, длина, о которой я говорю, это длина комментария на этом форуме. Я не говорю о длине запроса. Можете ли вы создать очень простой пример определения сетки, определяющий начальный фильтр? Я пробовал все, что мог, используя все ваши демонстрации, и ничто не дает идеального универсального решения. У меня есть настраиваемая фильтрация с нумерацией страниц по умолчанию, которая отлично работает. Но я просто не могу установить фильтр по умолчанию, ИСПОЛЬЗУЯ GRID CONSTRUCT. Вы говорите, что нет, но я уверяю вас, что пытался определить начальные фильтры postData.filters - у меня не работает. Кстати, используя GET (по умолчанию) и отправляя только два крошечных параметра - person Chance; 25.08.2018
comment
@Chance: Я могу только догадываться о причине вашей проблемы, потому что вы описываете ее, а не публикуете фрагменты кода. Я уже писал вам, что демонстрация является примером начальной загрузка. Вы можете использовать инструменты разработчика Chrome/IE (вкладка «Сеть»), чтобы увидеть этот первоначальный запрос Ajax к URL-адресу http://www.ok-soft-gmbh.com/jqGrid/OK/sortfunc.json?filters={"groupOp":"AND","groups":[],"rules":[{"field":"isFinal","op":"eq","data":"1"}]}&_search=true&nd=1535213227354&rows=10000&page=1&sidx=taskId&sord=asc (в закодированной форме). - person Oleg; 25.08.2018
comment
@Chance: Таким образом, если на сервере будет реализована фильтрация на стороне сервера, то фильтрация на стороне клиента, используемая в демонстрации, не потребуется. Насколько я знаю, ваш тест кода сервера для параметров _search=true и filters. Таким образом, он должен возвращать отфильтрованные заказы уже для начальной загрузки. Вам нужно просто установить filters на значение начального фильтра. - person Oleg; 25.08.2018

Извините за такой ответ, но этот вопрос начался с одной темы, связанной с фильтрацией и пейджингом, но с использованием внешнего источника фильтрации. На самом деле у Олега есть несколько демонстраций во многих потоках, которые я смог использовать для выполнения пользовательской фильтрации и поддержки встроенного пейджинга по умолчанию. Таким образом, его ответ будет принятым ответом на исходную тему вопроса.

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

Нашел еще один ответ Олега на совсем другой вопрос:

jqGrid - как настроить сетку, чтобы НЕ загружать какие-либо данные изначально?.

Олег ответил на этот вопрос, и этот ответ решил нашу вторую потребность загрузить один способ, а затем разрешить другой.

Итак, при начальной загрузке мы ищем параметры фильтра на стороне сервера. Не дано? Мы извлекаем записи, используя фильтрацию по умолчанию. Параметры присутствуют? Мы используем исходные предоставленные параметры. Разница с начальной загрузкой в ​​том, что мы не выходим из AJAX. Вместо этого мы json_encode данные и помещаем их в определение сетки следующим образом:

$('#grd_invoices').jqGrid(
...
url: '{$modulelink}&sm=130',
data: {$json_encoded_griddata},
datatype: 'local',
...
});

Поскольку тип данных установлен на «локальный», сетка изначально НЕ переходит на сервер, поэтому параметр данных используется сеткой. Когда мы готовы фильтровать, мы используем решение Олега из еще одного ответа на еще один вопрос, чтобы динамически применить фильтр следующим образом:

var myfilter = { groupOp: 'AND', rules: []};
myfilter.rules.push({field:'fuserid',op:'eq',data:$('#fuserid').val()});
myfilter.rules.push({field:'finvoicenum',op:'eq',data:$('#finvoicenum').val()});
myfilter.rules.push({field:'fdatefield',op:'eq',data:$('#fdatefield').val()});
myfilter.rules.push({field:'fsdate',op:'eq',data:$('#fsdate').val()});
myfilter.rules.push({field:'fedate',op:'eq',data:$('#fedate').val()});
myfilter.rules.push({field:'fwithin',op:'eq',data:$('#fwithin').val()});
myfilter.rules.push({field:'fnotes',op:'eq',data:$('#fnotes').val()});
myfilter.rules.push({field:'fdescription',op:'eq',data:$('#fdescription').val()});
myfilter.rules.push({field:'fpaymentmethod',op:'eq',data:$('#fpaymentmethod').val()});
myfilter.rules.push({field:'fstatus',op:'eq',data:$('#fstatus').val()});
myfilter.rules.push({field:'ftotalfrom',op:'eq',data:$('#ftotalfrom').val()});
myfilter.rules.push({field:'ftotal',op:'eq',data:$('#ftotal').val()});
myfilter.rules.push({field:'fmake',op:'eq',data:$('#fmake').val()});
myfilter.rules.push({field:'fmodel',op:'eq',data:$('#fmodel').val()});
myfilter.rules.push({field:'fserial',op:'eq',data:$('#fserial').val()});
myfilter.rules.push({field:'fitemid',op:'eq',data:$('#fitemid').val()});
myfilter.rules.push({field:'ftaxid',op:'eq',data:$('#ftaxid').val()});
myfilter.rules.push({field:'fsalesrepid',op:'eq',data:$('#fsalesrepid').val()});

var grid = $('#grd_invoices');
grid[0].p.search = myfilter.rules.length>0;
$.extend(grid[0].p.postData,{filters:JSON.stringify(myfilter)});
$('#grd_invoices').jqGrid('setGridParam',{datatype:'json'}).trigger('reloadGrid',[{page:1}]);

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

Кредит принадлежит Олегу, потому что я использовал многие из его сообщений из многих вопросов, чтобы достичь конечного результата. Спасибо @Олег!

person Chance    schedule 24.08.2018