[РЕШЕНО] Hidden element не обновляется в hook_insert & hook_update

Главные вкладки

Аватар пользователя bratello bratello 2 июля 2010 в 14:22

В hook_form отправляю некую json структуру в скрытом поле (hidden element).

<?php
$form
['myfield'] = array(
    
'#type'     => 'hidden',
    
//'#input'    => true, //Input флаг ситуацию не изменил
    
'#value'    => drupal_to_js($mystructure),
    
'#attributes'  => array('class' => 'myfield_class')
  );
?>

На клиентской стороне javascript разбирает эту структуру, пользователь может менять содержимое этой структуры, на сабмит структура обратно сериализуется в скрытом поле и отправляется на сервер, но ни в hook_validate, hook_insert & hook_update в поле node обновления не приходят, там находится старое значение. Навигатор обновленные данные в POST отправляет, на стороне сервера в $_POST данные тоже приходят, но в $node->myfield старые данные. Пока что разбираю структуру из $_POST, но хотелось бы разобраться.

Комментарии

Аватар пользователя kosilko kosilko 2 июля 2010 в 16:33

в друпале скрытые инпуты защищены от изменений клиентом. Если уж так решили действовать, то делайте скрытый стилями текстфилд.

Аватар пользователя bratello bratello 2 июля 2010 в 19:02

"kosilko" wrote:
А вы попробуйте. Всего лишь - input на textfield поменять, давно бы уже сделали.

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

Аватар пользователя kosilko kosilko 2 июля 2010 в 19:09

"bratello" wrote:
Я просто пытаюсь понять смысл зачем хиден филд сделали только для чтения?

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

Аватар пользователя gorr gorr 2 июля 2010 в 20:43

Да, действительно, все элементы, у которых изначально задано значение '#value' не передают значения из $_POST в массив $form_state['values']. Можно обойти, создав элемент custom_hidden, который будет отличаться темой от стандартного элемента hidden, подставляя '#default_value' в инпут вместо '#value'.
<?php
function mymodule_elements() {
$elements['custom_hidden'] = array('#input' => TRUE, '#process' => array('form_expand_ahah'), '#theme' => 'theme_custom_hidden');
return $elements;
}
?>

<?php
function theme_custom_hidden($element) {
return '\n";
}
?>

Аватар пользователя bratello bratello 2 июля 2010 в 23:36

Гор, генитально! оказывается имплементировать ничего не нужно было, а просто правильно прочитать документацию:

#default_value
Used by: checkbox, checkboxes, date, hidden, radio, radios, select, textarea, textfield, token, weight

Description: The value of the form element that will be displayed or selected initially if the form has not been submitted yet. Should NOT be confused with #value, which is a hard-coded value the user cannot change!

Таким образом решение выглядит следующим образом:

<?php
$form['myfield'] = array(
'#type' => 'hidden',
'#default_value' => drupal_to_js($mystructure),
'#attributes' => array('class' => 'myfield_class')
);
?>

Самое грустное что в документации был пример использования скрытого поля, и именно с #value, и ни слова о заморочках. Я считаю это недостаток документации.

Аватар пользователя Xermit Xermit 23 августа 2010 в 0:10

Подниму тему вновь, как раз сейчас этим занимаюсь, хотелось бы справедливости и истины ради узнать, действительно ли так как gorr описал.

У меня как раз ситуация ровно наоборот, в form_alter хуке я добавляю свое поле textfield, устанавливаю у него значение #default_value в пустую строку, далее в этом же хуке я указываю свою функцию $form['#after_build'][] = 'myform' (заметьте для after_build);

в которой я уже для этого поля прописываю значение #value, то есть уже после того как все собралось, я инициализирую свои поля,

в form_alter я включаю свой submit обработчик, чтобы выдрать значение своего textfield-а
$form['buttons']['submit']['#submit'] = array_merge(array('mysubmit'), $form['buttons']['submit']['#submit']);

и в своем обработчике я обращаюсь к значению этого поля как
$form_state['values'][...]
и получаю его
при этом на странице я это поле изменяю, где бы почитать это углубленно а то fapi недостаточно.
чувствую что вы тоже может быть правы.

попробую тут по новой разобраться тоже с hidden элементами, если смотреть fapi то в общем то не должно быть там таких проблем, там даже явно указано, что
Note that if you plan to use JavaScript to change your hidden element's value, you will need to use the #default_value property rather than #value.
то есть как раз то что вы практически сказали, но эот было написано чисто для hidden элемента.

Еще полезным думаю будет элемент типа value использовать, по сути это как hidden для формы, только никогда для клиента не передается, и он никогда ее не увидет, своего рода сессионая переменная на стороне сервера.

Вот еще что, если значение моего поля textfield не перекинуть куда нибудь в cck поле материала, то оно увы не сохранится для него при вызове preview или submit, поэтому я в своем submit обработчике перекидываю данные из $form_state['values'][...] куда нибудь, так как при form_alter в $form_state их точно нет.

Кажется теперь я понял что вы имели ввиду. Что в submit обработчике они будут, а вот в form_alter в form_state при построении формы после сохранения и для последующего редактирования или предпросмотра их уже не будет.

Исследовал этот вопрос и путем распечатки логов выяснил что моя функция для after_build состояния при построениии формы (после нажатия кнопки preview) вызывается два раза, при первом вызове в form_state['values'] для моего textfield в самом деле есть значение которое я указал в поле на странице, а вот при повторном вызове в качестве значения указано то, что я когда то указал для textfield в свойстве #default_value.

Соответственно, чтобы не потерять значение этого поля на пути между моим submitom и следующим отображение формы редактирования для предпросмотра приходится его в реальное cck поля перекинуть или перекинуть в поле типа value или в $form['#myvar']='значение' (об этом здесь написано http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....), чтобы потом в form_alter #value проинициализировать (ведь пользователь не должен потерять что когда то ввел в форме после нажатия кнопки предпросмотр).

Все таки весьма сложная для понимания система, мозги уже почти вытекли.