jqGridPHP - таблицы на ajax без головной боли

fandm

Новичок
Пока раскопки остановились на том, что в исходниках jqGrid collapseRow и collapseNode выполняются при сворачивании узла для всех Rows, которые возвращаются функцией getNodeChildren (в итоге таким Rows прописывается display:none; и это воспроизводит эффект сворачивания). Так вот, эта функция ничего не возвращает, т.е. тупо пустая строка. В итоге получается, что как бы нет дочерних Rows и потому некому делать collapse - вот и получается, что иконка меняется, а сворачивание не происходит. Теперь пытаюсь понять почему getNodeChildren может ничего не возвращать...Там внутри считывается $t.p.treeReader.parent_id_field, он равен "parent" и мы такое поле заполняем как раз в parseRow, верно? В getNodeChildren для каждого Row опрашивается его parent_id и, если он равен тому узлу, который мы сейчас хотим свернуть, то такой Row добавляется в массив дочерних Rows. Так вот, в моём случае для всех Row, почему-то, parent = null...

Всё, разобрался. :) :) :) Оказывается полем, которое выполняет роль parent, используется в query, но я для него забыл прописать столбец в colModel, поэтому оно не попало в select-часть и поэтому оно не было доступно в parseRow, т.е. для всех Rows parent в итоге был равен null. :) Всё просто.

Так что не забывайте прописывать в colModel столбец для поля parent! ;)
 

fandm

Новичок
А вот указание $r['expanded'] = true; всё равно не даёт результата. Иконка узла становится такая, как если бы он был раскрыт, а узел при этом не раскрыт. Такое ощущение, что это св-во справедливо только для datatype == "local"...

Что примечательно... Если использовать совет отсюда, то работает (только если оформить этот код в виде кнопки, которую необходимо дополнительно нажать), но работает только для root-узла, оно и понятно, ведь остальные узлы появятся только после Ajax-запроса на сервер. А при повторном нажатии, когда уже получены дочерние узлы, некоторые из них раскрываются, а некоторые - нет и даже "теряют" свои дочерние Rows, т.е. их уже невозможно раскрыть даже вручную. На автомате на тот же gridComplete отрабатывает так, что, опять-таки, меняется только иконка узла, а узел остаётся свёрнутым. Не понятно...
 

~WR~

Новичок
Посмотрел. Они что-то намутили в последних апдейтах treeGrid и не обновили документацию.
В конец добавился еще один параметр - loaded.

Обновил основной jqGrid-класс, чтобы он автоматом добавлял loaded=true.
Работает: http://jqgrid-php.net/examples/?render=jqOutTreeFull&expanded=1

Перекачайте с гитхаба.
 

~WR~

Новичок
Не, всё не так просто. Видимо, loaded обозначает, что дети узла уже загружены с сервера.
Соответственно, для обычного treeGrid нужно ставить loaded=false, для полностью загруженного - true.

Ну и плюс можно сделать частичную загрузку. Каких-то детей загрузить, а каких-то - нет.
Видимо, кому-то понадобилось такое. :)

Перекачайте еще раз. Надеюсь, последний коммит по этой проблеме.
Старые treeGrid будут работать без изменений. По умолчанию loaded - false.
 

fandm

Новичок
Эммм..... Так я таки правильно понял, что "заэкспандить" узел таким способом можно только в том случае, если дерево подгружено полностью, т.е. не используется порционность подгрузки узлов через Ajax?
Т.е., если мне всё-таки нужен Ajax, но необходимо, чтобы root-узел сразу раскрылся, то $r['expanded'] = true; и $r['loaded'] = true; не помогут?..
 

fandm

Новичок
В общем, вариант
PHP:
				gridComplete: function() {
					setTimeout(function(){
						$("#jqGrid").find(".treeclick").trigger('click');
					}, 0);
				},
частично решает проблему, но, как я уже писал выше, как-то криво... root-узел раскрывается, но последующая попытка раскрыть другие узлы вручную приводит к странному результату, раскрываешь один узел, а раскрывается совершенно другой...

Не понимаю как можно решить такую задачу: дерево должно быть построено с учётом Ajax, т.е. узлы раскрываются поэтапно через Ajax-запросы, но при этом необходимо, чтобы головной root-узел был раскрыт сразу.
 

fandm

Новичок
Всё, решил для себя таким образом:
PHP:
				gridComplete: function() {
					var rData = $grid.jqGrid('getGridParam', 'data');
					if(rData[0]){
						setTimeout(function(){
							$grid.jqGrid().expandRow(rData[0]); 
							$grid.jqGrid().expandNode(rData[0]); 
						}, 0);
					}
				}
Обычный TreeGrid (с использованием Ajax) загружается и сразу же раскрывается root-узел (нулевой).

Необходимость setTimeout() с нулевым таймаутом описана здесь.
 

~WR~

Новичок
Залил обновление. Добавился поиск по комплексным фильтрам:
http://jqgrid-php.net/examples/?render=jqOutAdvancedSearch

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

С тем, как это работает в деталях, можно ознакомиться здесь:
https://github.com/wildraid/jqGridPHP/blob/master/php/jqGrid.php#L1261

Добавлена поддержка treegrid типа nested. Все то же самое, что и в adjacency, только вместо колонки parent будут lft и rgt.

Теперь практически вся функциональность jqGrid покрыта серверной частью.
Думаю, через недельку можно будет выпускать нормальный релиз. Есть у кого свободный инвайт на хабр? :)
 

Skoff

Новичок
Всем привет! Извините за ламерский вопрос. Мне нужно вывести из базы все строчки у которых колонка ban=0. Вот что пробовал я и ничего с этого не вышло:
PHP:
$this->query  = "
				SELECT {fields} 
				FROM (
					SELECT id, lang, word, pop, ban FROM requests WHERE ban=0
					)
				WHERE {where}
				";
Пожалуйста, помогите решить проблему
 

~WR~

Новичок
1). Добавить в функцию init:
PHP:
$this->where[] = 'ban=0';
2). Или как-то так:
PHP:
$this->query = "SELECT {fields} FROM requests WHERE {where} AND ban=0";
Если все же используем под-запрос, то ему нужно дать имя после закрывающей скобки. Как-то так:
PHP:
SELECT {fields} 
FROM (
    SELECT id, lang, word, pop, ban FROM requests WHERE ban=0
) a
 WHERE {where}
Я букву 'a' добавил.
Хотя в MySQL может и не обязательно так делать.

P.S. Если включен debug-режим, то, в случае ошибок, там возвращается JSON-ответ с конкретным сообщением, что пошло не так. И там же прямо запрос, на котором все обрушилось. Должно помочь.
 

Skoff

Новичок
~WR~, огромное спасибо! Просто я не разобрался как их правильно строить и сам себя запутал))
 

~WR~

Новичок
Поправил ошибку с залочиванием грида при экспорте в Excel в IE.
 

yadenis

Новичок
Здравствуйте, интересует пример с вложенными таблицами.

При выводе мы получаем id родительского элемента через $this->input, а как получить его при добавлении нового элемента во вложенную таблицу?

Попытался перегрузить opAdd, но так и не нашел способа вытащить идентификатор, он почему-то всегда у меня NULL :(

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

fandm

Новичок
Может кому-то пригодится.
Для очистки фильтра по всем столбцам:
PHP:
		function ClearFilter(gridid) {
			$('#gbox_'+gridid).find('input:text[id^="gs_"]').each(function(){
				$(this).val('');
			});
		}
Для сброса фильтра:
PHP:
						setTimeout(function(){
							$grid[0].triggerToolbar();
						},0);
Если непосредственно перед очисткой фильтра в гриде было инициировано ajax-обращение (reload, sorting, paging и т.д.), то сброс фильтра необходимо выполнять на loadComplete, иначе не сработает.

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

~WR~

Новичок
Для редактирования у них там отдельные массивы с доп. параметрами (editData и delData):
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing

Соответственно, нужно их тоже заполнять при рендеринге. Либо ставить callback'и на serializeEditData и serializeDelData.
Если у вас сделано всё как в примере, то можно просто на три строчки расширить функцию renderComplete.

PHP:
protected function renderComplete($data)
{
    #Add condition to postData
    $data['options']['postData']['customer_id'] = $data['suffix'];

    #Add customer_id to edit module
    $data['nav']['prmAdd']['editData']['customer_id'] = $data['suffix'];
    $data['nav']['prmEdit']['editData']['customer_id'] = $data['suffix'];
    $data['nav']['prmDel']['delData']['customer_id'] = $data['suffix'];
    
    return parent::renderComplete($data);
}
Вместо customer_id пишите название своей колонки, в которой хранится id родителя.
По идее, всё. Значение будет отсылаться на сервер, и оно будет доступно в input'е.
 

~WR~

Новичок
Для очистки фильтра по всем столбцам:
Если это реально нужно, то лучше как-то так:
PHP:
$grid.closest('.ui-jqgrid-view').find('.ui-search-toolbar :input').val('');
Работает также с select'ами и не зависит от возможных будущих изменений в верстке jqGrid.
Хотя, по-моему, стандартный clearToolbar не хуже. :)
 

fandm

Новичок
Спасибо, не нашёл в своё время этой функции. Но, насколько я понял, эта функция сразу инициирует ajax-запрос, чтобы "реально сбросить фильтр", а это не всегда требуется. :) Например, если сразу же за очисткой необходимо присвоить новый фильтр, а уже только потом сделать post. Т.е. когда не хочется многочисленных бесполезных обращений к серверу. Вот если бы у этой функции был какой-то параметр аля postnow.
С такими вещами однозначно сталкиваешься, когда используешь jqGrid в разработке сложного Web-приложения с многочисленными диалогами с вложенными гридами.
С Вашим вариантом согласен, он более приемлемый. :)

EDIT:
А, пардон, там есть такой параметр: trigger. Если он равен false, то обращения на сервер не будет, пока мы его не сделаем сами. Спасибо ещё раз, ступил. :)

EDIT 2:
Только я бы всё равно сначала проходил по всему toolbar-у и проверял был ли там фильтр, а то, если его там не было, то получаются обращения к серверу впустую.
 

Jnas

Новичок
Здравствуйте! Извините за ламерский вопрос и за ламерские вопросы, которые еще будут.
увидел скрин

подозреваю что это делается не в таблице но всё же спрошу, как сделать как в рисунке , выбор таблиц "Закупка","Закупка2" и т.д.
 
Сверху