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

fandm

Новичок
Ага, было дело, уже не по помню из-за чего. Я дописывал в jqgrid-ext.js в 25-й строке (ну так, на всякий случай)
PHP:
if(obj && obj.error)
UPDATED
А, вспомнил... Я раньше использовал обработчик события afterSubmit в вызове editGridRow, а в конце не возвращал обязательный массив из 3-х значений, где нулевой элемент массива является флагом наличия ошибочной ситуации. Вот здесь есть незаметная, но весьма важная фраза
When used this event should return array with the following items [success, message, new_id]
Если этот флаг false (т.е. не success), то это расценивается как ошибочная ситуация. А на самом-то деле ошибки нет и в obj (т.е. в json-ответе) нет поля error.
sirba,
может у Вас как раз такая ситуация?
 

sirba

Новичок
Спасибо за ответ, скажите пожалуйста а можно в дереве после .trigger("reloadGrid"); сохранять его состояние - открытые узлы
 

fandm

Новичок
а можно в дереве после .trigger("reloadGrid"); сохранять его состояние - открытые узлы
Я так и не разобрался с expanded узлами. У себя делаю раскрытие root-узла уже на клиенте после полной загрузки дерева. А так вообще есть в parseRow $r['expanded'], но на что оно влияет и при каких условиях я так и не понял до конца. По-моему, это сугубо для datatype=local, но я могу и ошибаться. Больше по этому вопросу расскажет ~WR~
 

~WR~

Новичок
Насколько я понимаю, сейчас схема следующая.
Чтобы узел развернут сразу после загрузки, у него должны стоять параметры expanded=true и loaded=true.

Expanded говорит о состоянии узла - открыт или закрыт.
Loaded говорит о том, что дети узла уже загружены, и обращаться за ними на сервер не надо.

Конкретный пример структуры:
PHP:
Книги {expanded=true, loaded=true}
|-- Художественная литература {expanded=false, loaded=false}
|-- Научная литература {expanded=true, loaded=true}
|-- -- Влияние вулканов на миграцию рыб {isLeaf=true}
|-- -- Влияние миграции рыб на вулканы {isLeaf=true}
Будут раскрыты узлы "Книги" и "Научная литература".
Примерно такую последовательность рядов нужно собирать в ответе от сервера. Способ сборки любой, какой вам больше нравится. Единственное - важно помнить о том, что ряды должны идти в правильном порядке. Дети сразу после родителей.

id раскрытых рядов перед обновлением проще всего собирать jQuery селектором.

PHP:
var ids = [];
$grid.find('.tree-minus').closest('.jqgrow').each(function()
{
    ids.push($(this).attr('id'));
});

Я дописывал в jqgrid-ext.js в 25-й строке (ну так, на всякий случай)
Правильно. Без понятия, почему оно при сортировке приходит в errorHanlder, да еще и с пустым аргументом. По-моему, раньше сортировка деревьев вообще отключалась еще на старте. Вечером добавлю фикс.
 

fandm

Новичок
Единственное - важно помнить о том, что ряды должны идти в правильном порядке. Дети сразу после родителей.
Во-во... Вот потому я и не стал заморачиваться и сделал раскрытие нужного мне узла уже на клиенте. Зато запрос обыкновенный, аля id и parent_id, без построения готового дерева в результате запроса. Но, конечно же, если нужно, чтобы было раскрыто сразу несколько узлов, то такой вариант не подойдёт, надо делать через expanded и loaded.
 

fandm

Новичок
~WR~,
посоветуйте, пожалуйста, как правильно поступить.
Изменил штатную функцию columnChooser. Изменил цикл заполнения перечня столбцов вот так:
PHP:
var colName;

        select.empty();
        $.each(colModel, function(i) {
            colMap[this.name] = i;
            if (this.hidedlg) {
                if (!this.hidden) {
                    fixedCols.push(i);
                }
                return;
            }
			
			if(colModel[i].hgroup){
				colName = self[0].p.groupHeaderWR[colModel[i].hgroup].label + ' | ' + colNames[i];
			}else{
				colName = colNames[i];
			}

            select.append("<option value='"+i+"' "+
                          (this.hidden?"":"selected='selected'")+">"+colName+"</option>");
        });
, чтобы названия столбцов добавлялись с учётом названия группы, если таковая имеется. Необходимость такого изменения возникла ввиду того, что в моих гридах часто-густо встречаются столбцы с одинаковыми названиями, но принадлежат они разным группам. Чтобы пользователю было легче ориентироваться при сокрытии/визуализации столбцов, я и сделал такое изменение. Но изменение это я внёс пока тупо в jquery.jqGrid.src.js, что есть, разумеется, некорректно.

Как правильнее поступить в данном случае? Написать наследника этой функции в jgrid-ext.js? И для этого придётся, по сути, повторить код этой функции + моё изменение?
 

Polina

Новичок
Здрасте.
В ходе разбора полетов не смогла сделать следующее
1) есть несколько столбцов имеют они все параметр
PHP:
'editoptions' =>  array('value'=> new jqGrid_Data_Value(array(1 => "Неизменно" , 2 => "Отменить", 3 => "Выполнить"))),
2) Делаю следующее
PHP:
	     protected function opEdit($id, $upd)
			{	date_default_timezone_set("Europe/Moscow");
				$vrem = date('Y-m-d H:i:s');
				if($upd['vikup_otkrit'] == '3') {$upd['vikup_otkrit']=$vrem;} elseif ($upd['vikup_otkrit'] == '2') {$upd['vikup_otkrit']=NULL;}else{die();}
				return parent::opEdit($id, $upd);
			}
Так вот , в таком случае , если я выбираю "Неизменно" срабатывает die , то столбец остается неизменным, как я планировала. Но вот если у меня таких несколько столбцов, как мне тогда это организовать ?
По ясным причинам не получиться вставить несколько строк на подобие
PHP:
 if($upd['vikup_otkrit'] == '3') {$upd['vikup_otkrit']=$vrem;} elseif ($upd['vikup_otkrit'] == '2') {$upd['vikup_otkrit']=NULL;}else{die();}
ЗЫ Кстати спасибо за предыдущие подсказки. там была моя ошибка поэтому datapicker не работал))
 

~WR~

Новичок
Как правильнее поступить в данном случае? Написать наследника этой функции в jgrid-ext.js?
Да нормально. JS он и есть JS.
Если там есть event на появление columnChooser'а, то можно в нем пробежаться уже по готовому html и напрямую внести свои изменения.

Polina
unset($upd['vikup_otkrit']) вместо die.
Те колонки, которых нет в $upd, он не обновляет.
 

fandm

Новичок
Да нормально. JS он и есть JS.
Спасибо, уже, в принципе, так и сделал, просто думал есть какой-то способ наследования, чтобы не плодить избыточный код.
Если там есть event на появление columnChooser'а
А вот это мысль, спасибо, гляну. :) В принципе диалог columnChooser'а такой же диалог, как и все остальные, а значит событие open в нём тоже должно быть.
 

fandm

Новичок
~WR~,
ещё, если можно, вопрос.
В методе render есть возможность передать дополнительный параметр - переопределение опций грида.
Т.е., я, например, пишу:
PHP:
var opts = 
{
	colModel : 
	[ 
		{ "label": "Test1", "name": "id", "index": "id" }, 
		{ "label": "Test2", "name": "folder_type", "index": "folder_type" }
	]
}
<?=$jq_loader->render('jqMyGrid', 'opts');?>
, т.е. я хочу как бы переопределить некоторые настройки некоторых столбцов, которые уже преднастроены в PHP классе грида.
Но в результате я получаю грид только с двумя столбцами "Test1" и "Test2". Но там исходно около 50 разных столбцов. :)

Собственно вопрос. А так вообще можно делать?
 

~WR~

Новичок
Вообще можно сделать все, но это очень уж странное.

Для объединения параметров используется самый простой способ: jQuery.extend:
http://api.jquery.com/jQuery.extend/

Можете в коде (внутри renderComplete в базовом классе) добавить первым аргументом в extend - true. Будет "глубокое" объединение.
 

~WR~

Новичок
Хотя нет - не поможет. colModel - это массив. Он никак не определит, какую колонку поменять.
Нужно писать свои функции для этого.

Но.. зачем?

Если что - $this->cols это простой массив. По нему можно и foreach'ем пробежаться при случае.
Зачем что-то делать на клиенте? В крайнем случае - есть setColProp.
 

fandm

Новичок
Зачем что-то делать на клиенте?
Вообще задача стояла такая. При нажатии на "Сохранить" в диалоге columnChooser настройки видимости и ширин столбцов сохранять в cookie (это было решено сразу и просто через $.cookie:
PHP:
			done : function(perm)
			{
				$grid.jqGrid("remapColumns", perm, true);
				$grid.jqGrid('updateGroupHeaderWR');
				var cookieColumns = {};
				var colModel = $.extend([],$grid.getGridParam("colModel"));
				if($grid.getGridParam("rownumbers")) {
				   colModel.splice(0,1);
				}
				$.each(colModel, function(i){
					if(!this.hidden){
						cookieColumns[this.name] = {w: this.width};
					}else{
						cookieColumns[this.name] = {};
					}
				});
				var json_text = JSON.stringify(cookieColumns, null);
				$.cookie("jqGrid_columns", json_text, { expires: 365 });
			},
), а при следующем выводе грида применять эти настройки снова.
Ну вот и захотелось сделать применение ранее сохранённых настроек ширин и видимости столбцов исключительно на клиенте. Если хотите, прихоть такая. :)
Если что - $this->cols это простой массив. По нему можно и foreach'ем пробежаться при случае.
Спасибо, уже так и сделал, тем более, что
он-то есть, но как раз параметр, например, width через него не поменяешь (ниже есть абзац "Below are options which can not be changed dynamically when the grid is constructed"). Для видимости/невидимости, конечно, имеются отдельные методы showCol и hideCol. :)
Для объединения параметров используется самый простой способ: jQuery.extend:
Ну, эт понятно, у Вас же ж в renderComplete и добавляется автоматом $.extend, если isset($data['extend']). Потому я и хотел воспользоваться сначала этой возможностью. И, если бы не ограничения самого jqGrid в плане динамического изменения некоторых св-в столбцов, то я бы, скорей всего, таки сделал бы всю работу на клиенте. Ну, фишка у меня такая, все интерфейсные манипуляции переложить исключительно на клиента. :)
Но, Бог с ним, на сервере, так на сервере. :)
Делаю так:
PHP:
		if(isset($_COOKIE['jqGrid_columns'])){
			$new_cols = array();
			$colModel = json_decode($_COOKIE['jqGrid_columns'],true);
			foreach($colModel as $name=>$col){
				if(isset($col['w'])){
					$this->cols[$name]['hidden'] = false;
					$this->cols[$name]['width'] = $col['w'];
				}else{
					$this->cols[$name]['hidden'] = true;
				}
				$new_cols[$name] = $this->cols[$name];
			}
			$this->cols = $new_cols;
		}
Т.е. применяются ширины, видимость и порядок следования столбцов.

P.S. Уже в этой ветке начинает вырисовываться целый ряд "полезных примочек" для jqGrid/jqGridPHP, можно их даже в некий глоссарий оформить, в шапке ветки, например. ;)
 

fandm

Новичок
Может кому-то пригодится.
Если переопределяете у грида событие resizeStop (факт изменения ширины столбца), то не забывайте в обработчике этого события в конце добавлять:
PHP:
$grid.jqGrid('updateGroupHeaderWR');
, если используете группировку шапки грида по методу уважаемого ~WR~.
А то получается ситуация, что ширина столбца в области данных изменилась, а в шапке осталась старой. :)
 

fandm

Новичок
~WR~,
такой ещё вопрос. Если у столбца в formatter указана своя функция форматирования вывода, то метод extExport это не учитывает и в Excel выдаёт первоначальное содержимое ячеек такого столбца. Как правильно сделать, чтобы и в Excel данные попадали в таком же виде, как они выглядят в гриде? Подозреваю, что надо где-то дополнительно вызывать ту свою функцию форматирования, но где именно?
 

~WR~

Новичок
Форматировать на сервере в parseRow.
Все остальные способы - полная шняга.

Кстати, в parseRow всегда можно узнать, какой будет способ вывода рядов.
Просто проверяйте переменную $this->out. Имя по аналогии от дополнительной входящей переменной _out.
 

fandm

Новичок
Форматировать на сервере в parseRow.
Спасибо. Т.е. получается, по сути, надо писать дубликат клиентской JS-функции форматирования в PHP-коде?
Просто проверяйте переменную $this->out. Имя по аналогии от дополнительной входящей переменной _out.
Ага, понял, спасибо. Т.е. при экспорте $this->out = 'export'. Верно?
 

~WR~

Новичок
Спасибо. Т.е. получается, по сути, надо писать дубликат клиентской JS-функции форматирования в PHP-коде?
Можно убрать JS-функцию и оставить только серверную часть.

Подумайте сами: другие варианты подразумевают, что ваши данные сначала уйдут в браузер. Там их обработает JS и вернет обратно на сервер. Там они должны собраться в XLS файл и опять вернуться в браузер, но уже в виде iframe'а с документом. Полный кошмар, особенно на больших dataset'ах.

Yes.
 

fandm

Новичок
Подумайте сами: другие варианты подразумевают, что ваши данные сначала уйдут в браузер. Там их обработает JS и вернет обратно на сервер. Там они должны собраться в XLS файл и опять вернуться в браузер, но уже в виде iframe'а с документом. Полный кошмар, особенно на больших dataset'ах.
Я имел в виду не именно случай с экспортом в XLS, а двоякий случай, когда уже используется форматированный вывод в грид путём указания JS-функции в св-ве formatter и тут требуется дописать PHP-функцию для форматирования экпорта в XLS. Теперь же, если я правильно Вас понял, имеет смысл сделать PHP-функцию и использовать её в parseRow в обоих случаях: и при выводе в грид и при экпорте, т.е., по сути, отказаться от штатной возможности "formatter" в jqGrid?
А unformat-функцию на клиенте, получается, оставить? Ну, для случаев с редактированием записи. Тогда всё равно решение получается 50 на 50, частично на сервере, а частично на клиенте. Или я, всё-таки, неправильно Вас понял?
А то, что Вы описали, безусловно, не самый лучший вариант.
 

Polina

Новичок
Есть два вопроса, один по теме, другой не совсем. Начну в с первого:
1) Работа в субгриде. Есть столбец в субгриде
PHP:
	'id_polz'   =>array('label' => 'Поль.',
								
								'width' => 2,
								'align' => 'center',
								'editable' => true,
								),
условия субгрида
PHP:
	if($this->input('vari'))
					{
						$this->where[] = 'kilo.id_polz  = ' .'"'.($this->input('vari')).'"';
					}
Так вот не могу добавить запись в субгриде, быть точнее не заполняется поле kilo.id_polz , оно всегда пустое оказывается, пробывала через opEdit заполнить, к примеру
PHP:
	    protected function opEdit($id, $upd)
			{	
				$upd['id_polz'] = $this->input('vari');
	
				return parent::opEdit($id, $upd);
			}
, без успеха, результат один и тот же.
Как решить данную ситуация, самостоятельно самой создать запрос с INSERT INTO ?

2) с аяксом пока не очень, как сделать сворачивание таблицы, как в примерах http://trirand.com/blog/jqgrid/jqgrid.html ? Безымянный.png

заранее спасибки :)
 
Сверху