Здравствуйте. Подскажите, пожалуйста, как сделать так, чтобы при создании материала после выбора связанной ноды в CCK-поле Node Reference с автозаполнением в определенные поля этой формы автоматически подставились значения из определенных полей связанной ноды. Т.е. к примеру, если была выбрана связанная нода, то в поле "номер телефона" подставился телефон из соответствующего поля в связанной ноде, если в той ноде такое поле было заполнено.
Перерыл кучу модулей на тему Node Reference, пока безуспешно. Есть ли готовое решение? Или придется писать самому модуль с ajax-запросом к связанной ноде? Вот только не могу понять, как получить nid связанной ноды из CCK-поля с autocomplete, пока нода не была сохранена. Через Rules тут тоже не получится, т.к. нужно подставить значения в поля сразу как только в главном Node Reference поле через автозаполнение была указана связанная нода.
Подскажите, в общем, как сделать такую функциональную возможность.
Комментарии
могу предположить что hook_nodeapi вам поможет, делаете хук, читаете что заполнили в поля, загружаете ноду из референс поля, и переносите значения из нее в нужные вам поля и сохраняете.
Думаю как-то так.
Спасибо, но как я могу проверить, что записано в БД, если туда еще ничего не было записано? Нода ведь только создается, и мне нужно, чтобы как только была выбрана связанная нода, в другие поля формы создания материала тут же добавились данные из соответствующих полей связанной ноды. На этом этапе Node Reference только подставил значения в поле, но оно же еще не было записано в БД, или я что-то недопонимаю?
Данный хук прерывает создание ноды, но на этом этапе у вас уже есть готовый массив этой ноды с которым можно работать и изменять. Вам не нужно заходить в БД, все уже будет в этом массиве.
Т.е. как-то так: сначала я записываю в переменную $MY_REFERED_NODE_ID полученный из массива $node->content NID связанной ноды, потом добавляю его в произвольное поле?
<?php
$node->content['MY_REFERED_NODE_ID'] = array(
function MY_MODULE_NAME_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'view':
if ($node->type == 'MY_NODE_TYPE') {
$MY_REFERED_NODE_ID = $node->content['group_MY_GROUP_NAME']['group']['field_MY_REFERENCE_FIELD_NAME']['field']['items'][0]['#item']['nid'];
'#value' => $MY_REFERED_NODE_ID,
'#weight' => 1,
);
}
break;
}
}
?>
А дальше джаваскриптом считываю его, отправляю AJAX запрос на получение объекта связанной ноды, выдираю из него значение определенного поля, и записываю его в нужное поле данной формы создания материала?
Вопрос в том, сработает ли hook_nodeapi так как нужно? Т.е. сразу после того, как в "field_MY_REFERENCE_FIELD_NAME" (Node Reference поле с автозаоплнением) было установлено значение, запишется ли оно тут же в другое поле? И тут еще вопрос, на какой триггер повесить срабатывание Javascript?
Я дмал что вам надо нечто подобное:
<?php
$node->field_1 = $rnode->field_1;
function MY_MODULE_NAME_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'view':
if ($node->type == 'MY_NODE_TYPE') {
$MY_REFERED_NODE_ID = $node->content['group_MY_GROUP_NAME']['group']['field_MY_REFERENCE_FIELD_NAME']['field']['items'][0]['#item']['nid'];
$rnode = node_load($MY_REFERED_NODE_ID);
и т.д.
}
break;
}
}
?>
Зачем городить другие огороды, делайте сразу непосредственную запись в ноду а не в форму.
Если хотите через ajax чтобы значения подставлялись сразу в поля при выборе РЕФ ноды, то nodeapi тут не подойдет.
Тут нужно form_alter, изменить поле noderef добавив AHAH обработчик на выбор.
И потом с помощью функции реврайтить необходимы поля.
Если что спрашивайте, постараюсь помочь.
ПС:
<?php
$MY_REFERED_NODE_ID = $node->content['group_MY_GROUP_NAME']['group']['field_MY_REFERENCE_FIELD_NAME']['field']['items'][0]['#item']['nid'];
?>
мне кажется это неправильным!
<?php
$MY_REFERED_NODE_ID = $node->field_MY_REFERENCE_FIELD_NAME[0]['#item']['nid'];?>
нечто подобное должно быть короче
Да и чуть не пропустил: Вам нужна операция не view а presave!
Именно это мне и нужно.
А как с помощью hook_form_alter() на input-поле Node Reference можно повесить обработчик на какое-то событие?
Вообще, в этом плане сам функционал друпаловского Autocomplete не доработана - после выбора значение оно как-то интересно подставляется в поле: в отрендеренном поле на странице его видно, а если посмотреть через фаербаг, то у инпута в value ничего не значится... Записывалось бы оно туда сразу, тогда можно было бы на .change() этого value триггать срабатывание скрипта, считывать это значение, получать из него ID ноды и дальше по списку...
Может как-то через hook_menu_alter() переопределить вывод функции nodereference_autocomplete() из nodereference.module, хотя эта функция, судя по всему, просто выводит список подходящих под запрос значений, а выбор нужного все-равно делается скриптом Autocomplete. Походу его нужно ковырять, чтобы записывал его в параметр value этого input-поля...
Но я уже пытался надругаться над /misc/autocomplete.js, но никакие изменения в нем ни к чему не приводят: даже после удаления всех строк из него и очистки кэша, автозаполнение в этом поле все-равно работает...
hook_form_alter()
вы получите массив $form, который будет содержать все ваши поля.
обработчик ставится путем добавления массиву
<?php
$form['field_name']['#ahah'] => array (
'path' => //путь до php кода который возвращает данные в json формате
'wrapper' => //id элемента куда помещается результат
); ?>
path определяется хуком mymodule_menu()
подробнее можно почитать тут:
http://www.drupal.ru/node/44884
Точно, думал еще про #ahah, но не додумал Написал такой модуль:
<?php
$items['getrefferednodeid'] = array(
$form['reffered_node_id'] = array(
function referred_node_values_retrieve_menu() {
'page callback' => 'referred_node_values_retrieve_callback',
'access arguments' => array('access rights'),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function
referred_node_values_retrieve_form_alter(&$form, $form_state, $form_id) {'#value' => '<div id="reffered-node-id"></div>',
);
$form['field_NODE_REFERENCE_FIELD']['#ahah'] = array(
'path' => 'getrefferednodeid',
'wrapper' => 'reffered-node-id',
);
}
function
referred_node_values_retrieve_callback() {$reffered_node_id = $_POST['field_NODE_REFERENCE_FIELD'];
drupal_json(array('status' => TRUE, 'data' => $reffered_node_id));
}
?>
Но не работает: внутрь дива с id="reffered-node-id" ничего не добавляется. Я не уверен насчет "$_POST['field_NODE_REFERENCE_FIELD']" в коллбеке, но даже если переменной "$reffered_node_id" присвоить произвольный текст типа t('This is my refferef node id'), то этот текст все-равно после установки значения в поле node reference не добавляется внутрь дива "reffered-node-id"... Может тут нужно в параметре #ahah поиграться с #ahah['event']? Но ни 'blur' (который, по идее, по умолчанию подставляется), ни 'change' ни сработали.
К тому же не пойму прикола: не срабатывает функция "referred_node_values_retrieve_form_FORM_ID_alter", если ее использовать вместо "referred_node_values_retrieve_form_alter". Аналогично ничего не работает, если прописать условие на проверку ID формы используя "referred_node_values_retrieve_form_alter". Тип материала используется новый, но ID формы все-равно "node_form"...
<?php
'access arguments' => array('access rights'),
?>
Нет поддержки разрешений, поидее у вас нет доступа к этому коллбэку, нужно изменить:
<?php
'access callback' => 'referred_node_values_retrieve_acsess',
function
referred_node_values_retrieve_acsess() {return true;
}
?>
Это думаю не нужно:
<?php
$form['reffered_node_id'] = array(
'#value' => '<div id="reffered-node-id"></div>',
);
?>
Замените на:
<?php
$form['field_{any}']['#suffix'] = '<div id="reffered-node-id"></div>';
?>
Заменив {any} на любое ваше поле, которое уже есть форме.
И:
<?php
$reffered_node_id = $_POST['field_NODE_REFERENCE_FIELD'];
?>
при разработке используйте конструкцию:
<?php
drupal_set_message("<pre>".print_r($_POST,1)."</pre>");
?>
Это поможет увидеть вам с какого элемента массива или объекта брать значение.
Конструкцию можно использовать для проверки любой переменной в каждый момент времени.
Все сделал так, но ничего не получается. Вывод print_r($_POST,1) показывает, что массив пуст. Но даже не в этом дело. Как я говорю, даже если я присвою переменной $reffered_node_id произвольное значение для теста типа t('This is my refferef node id'), то при прямом обращении к пути, прописанного в #ahah, json выдает в data это значение, т.е. эта часть работает. А вот вот эта часть:
<?php
$form['field_NODE_REFERENCE_FIELD']['#ahah'] = array(
'path' => 'getrefferednodeid',
'wrapper' => 'reffered-node-id',
);
?>
не работает. Т.е. после выбора значения в этом поле, подсказанного автозаполнением, в див с ID "reffered-node-id" не происходит записи значения t('This is my refferef node id').
Я понял, видать я гдето пропустил то это поле с авто заполнением )
Авто заполнение это уже и есть ahah событие и второе на один и тот же элемент к сожалению не повесить.
Надо думать...
Я сомневаюсь что что-то может получится, в русском языке данное желание я всегда называю "и рыбку съесть и ... сесть".
Т.е. хотите чтобы от динамического элемента который меняется через яваскрипт происходило второе динамическое событие.
Но давайте попробуем следующий вариант, если хотите дальше экспериментировать:
Попробуем чистым JS тогда сделать, возможно получится сделать и ahah и js событие на 1 элемент, к тому же они будут разные.
1. Ставим обработчик на поле change или blur (не уверен), нужно проверить и другие эвенты
2. Передаем значение в нашу функцию php, где получаем значения тех полей что вам нужны
3. Передаем из php обратно в JS и напряму в поля записываем полученные результаты
Единственное я не уверен на счет первого пункта, получится или нет.
Да как бы если в целом подумать, то это не очень уж то и большой запрос: всего то, по сути, после выбора подходящего связанного материала подставить из него значения в другие поля той же формы. Но, как это часто бывает, довольно простой по логике вещей вопрос не так просто решить.
Главная проблема тут в том, что, как я уже писал, выбор нужного значения из результата, возвращаемого автозаполнением, как-то хитро записывается Javascript'ом в это поле. Он показывается в отрендеренном поле в браузере, но если глянуть в Firebug, или в моем случае в Opera Dragonfly, то в параметре value этого поля ничего нет - оно пустое. Соответственно тут и какой-то JS-ивент не повесишь и значение не считаешь, т.к. в DOM оно не прописано...
Поэтому, скорее всего, нужно изменять скрипт работы autocomplete, чтобы значение заносилось в value, и включать этот скрипт отдельным JS-файлом в самом конце. Вот только где изначальный его код? В /misc/autocomplete.js? Я пробовал его изменять, даже удалял все из него, и сам файл удалял, чистил кэш сайта и браузера, а в результате автозаполнение поля как работало, так и работает...
Есть такая штука в друпале:
jQuery(document).ajaxComplete(function(e, xhr, settings) {
if(!ahahCallback.i) {
ahahCallback.i = true;
alert(settings.url); //урл коллбэка
}
}
}
Это позволить добавить код после выполнения ahah колбэка, проверьте его.
расскажите пожалуйста, что в результате получилось и каким образом. Очень нужно сделать то же самое.
К сожалению, так и не удалось реализовать эту идею, так что подсказать ничем не могу. Если найдете решение, буду благодарен, если поделитесь им здесь.
А не подскажите материал по этому же вопросу, но только для Drupal 7?