Подстановка значений полей из связанной ноды после выбора в Node Reference Autocomplete

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

Аватар пользователя STINGER STINGER 14 мая 2012 в 16:48

Здравствуйте. Подскажите, пожалуйста, как сделать так, чтобы при создании материала после выбора связанной ноды в CCK-поле Node Reference с автозаполнением в определенные поля этой формы автоматически подставились значения из определенных полей связанной ноды. Т.е. к примеру, если была выбрана связанная нода, то в поле "номер телефона" подставился телефон из соответствующего поля в связанной ноде, если в той ноде такое поле было заполнено.

Перерыл кучу модулей на тему Node Reference, пока безуспешно. Есть ли готовое решение? Или придется писать самому модуль с ajax-запросом к связанной ноде? Вот только не могу понять, как получить nid связанной ноды из CCK-поля с autocomplete, пока нода не была сохранена. Через Rules тут тоже не получится, т.к. нужно подставить значения в поля сразу как только в главном Node Reference поле через автозаполнение была указана связанная нода.

Подскажите, в общем, как сделать такую функциональную возможность.

Комментарии

Аватар пользователя divined divined 14 мая 2012 в 17:13

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

Думаю как-то так.

Аватар пользователя STINGER STINGER 14 мая 2012 в 18:29

"divined" wrote:
могу предположить что hook_nodeapi вам поможет, делаете хук, читаете что заполнили в поля, загружаете ноду из референс поля, и переносите значения из нее в нужные вам поля и сохраняете.

Думаю как-то так.


Спасибо, но как я могу проверить, что записано в БД, если туда еще ничего не было записано? Нода ведь только создается, и мне нужно, чтобы как только была выбрана связанная нода, в другие поля формы создания материала тут же добавились данные из соответствующих полей связанной ноды. На этом этапе Node Reference только подставил значения в поле, но оно же еще не было записано в БД, или я что-то недопонимаю?

Аватар пользователя divined divined 15 мая 2012 в 10:09

Данный хук прерывает создание ноды, но на этом этапе у вас уже есть готовый массив этой ноды с которым можно работать и изменять. Вам не нужно заходить в БД, все уже будет в этом массиве.

Аватар пользователя STINGER STINGER 15 мая 2012 в 16:45

"divined" wrote:
Данный хук прерывает создание ноды, но на этом этапе у вас уже есть готовый массив этой ноды с которым можно работать и изменять. Вам не нужно заходить в БД, все уже будет в этом массиве.

Т.е. как-то так: сначала я записываю в переменную $MY_REFERED_NODE_ID полученный из массива $node->content NID связанной ноды, потом добавляю его в произвольное поле?

<?php
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'];

         

$node->content['MY_REFERED_NODE_ID'] = array(
            
'#value' => $MY_REFERED_NODE_ID
            
'#weight' => 1
         );
      }
    break;
  }
}
?>

А дальше джаваскриптом считываю его, отправляю AJAX запрос на получение объекта связанной ноды, выдираю из него значение определенного поля, и записываю его в нужное поле данной формы создания материала?

Вопрос в том, сработает ли hook_nodeapi так как нужно? Т.е. сразу после того, как в "field_MY_REFERENCE_FIELD_NAME" (Node Reference поле с автозаоплнением) было установлено значение, запишется ли оно тут же в другое поле? И тут еще вопрос, на какой триггер повесить срабатывание Javascript?

Аватар пользователя divined divined 16 мая 2012 в 10:56

Я дмал что вам надо нечто подобное:

<?php
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);

         

$node->field_1 $rnode->field_1;
         
и т.д.
      }
    break;
  }
}
?>

Зачем городить другие огороды, делайте сразу непосредственную запись в ноду а не в форму.

Аватар пользователя divined divined 16 мая 2012 в 11:04

Если хотите через 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'];?>

нечто подобное должно быть короче Smile

Аватар пользователя STINGER STINGER 16 мая 2012 в 15:08

"divined" wrote:
Если хотите через ajax чтобы значения подставлялись сразу в поля при выборе РЕФ ноды, то nodeapi тут не подойдет.

Именно это мне и нужно.

"divined" wrote:
Тут нужно form_alter, изменить поле noderef добавив AHAH обработчик на выбор.
И потом с помощью функции реврайтить необходимы поля.

А как с помощью hook_form_alter() на input-поле Node Reference можно повесить обработчик на какое-то событие?

Вообще, в этом плане сам функционал друпаловского Autocomplete не доработана - после выбора значение оно как-то интересно подставляется в поле: в отрендеренном поле на странице его видно, а если посмотреть через фаербаг, то у инпута в value ничего не значится... Записывалось бы оно туда сразу, тогда можно было бы на .change() этого value триггать срабатывание скрипта, считывать это значение, получать из него ID ноды и дальше по списку...

Может как-то через hook_menu_alter() переопределить вывод функции nodereference_autocomplete() из nodereference.module, хотя эта функция, судя по всему, просто выводит список подходящих под запрос значений, а выбор нужного все-равно делается скриптом Autocomplete. Походу его нужно ковырять, чтобы записывал его в параметр value этого input-поля...

Но я уже пытался надругаться над /misc/autocomplete.js, но никакие изменения в нем ни к чему не приводят: даже после удаления всех строк из него и очистки кэша, автозаполнение в этом поле все-равно работает...

Аватар пользователя divined divined 16 мая 2012 в 15:49

hook_form_alter()

вы получите массив $form, который будет содержать все ваши поля.

обработчик ставится путем добавления массиву

<?php
$form
['field_name']['#ahah'] => array (
        
'path' => //путь до php кода который возвращает данные в json формате
        
'wrapper' => //id элемента куда помещается результат
);

?>

path определяется хуком mymodule_menu()

подробнее можно почитать тут:
http://www.drupal.ru/node/44884

Аватар пользователя STINGER STINGER 16 мая 2012 в 19:06

Точно, думал еще про #ahah, но не додумал Smile Написал такой модуль:

<?php
function referred_node_values_retrieve_menu() {

     

$items['getrefferednodeid'] = array(
        
'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) {

    
        

$form['reffered_node_id'] = array(
           
'#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"...

Аватар пользователя divined divined 16 мая 2012 в 19:26
<?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>");
?>

Это поможет увидеть вам с какого элемента массива или объекта брать значение.
Конструкцию можно использовать для проверки любой переменной в каждый момент времени.

Аватар пользователя STINGER STINGER 16 мая 2012 в 23:39

Все сделал так, но ничего не получается. Вывод 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').

Аватар пользователя divined divined 17 мая 2012 в 10:03

Я понял, видать я гдето пропустил то это поле с авто заполнением )
Авто заполнение это уже и есть ahah событие и второе на один и тот же элемент к сожалению не повесить.

Надо думать...

Аватар пользователя divined divined 17 мая 2012 в 11:20

Я сомневаюсь что что-то может получится, в русском языке данное желание я всегда называю "и рыбку съесть и ... сесть".

Т.е. хотите чтобы от динамического элемента который меняется через яваскрипт происходило второе динамическое событие.

Но давайте попробуем следующий вариант, если хотите дальше экспериментировать:

Попробуем чистым JS тогда сделать, возможно получится сделать и ahah и js событие на 1 элемент, к тому же они будут разные.

1. Ставим обработчик на поле change или blur (не уверен), нужно проверить и другие эвенты
2. Передаем значение в нашу функцию php, где получаем значения тех полей что вам нужны
3. Передаем из php обратно в JS и напряму в поля записываем полученные результаты

Единственное я не уверен на счет первого пункта, получится или нет.

Аватар пользователя STINGER STINGER 17 мая 2012 в 13:14

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

Главная проблема тут в том, что, как я уже писал, выбор нужного значения из результата, возвращаемого автозаполнением, как-то хитро записывается Javascript'ом в это поле. Он показывается в отрендеренном поле в браузере, но если глянуть в Firebug, или в моем случае в Opera Dragonfly, то в параметре value этого поля ничего нет - оно пустое. Соответственно тут и какой-то JS-ивент не повесишь и значение не считаешь, т.к. в DOM оно не прописано...

Поэтому, скорее всего, нужно изменять скрипт работы autocomplete, чтобы значение заносилось в value, и включать этот скрипт отдельным JS-файлом в самом конце. Вот только где изначальный его код? В /misc/autocomplete.js? Я пробовал его изменять, даже удалял все из него, и сам файл удалял, чистил кэш сайта и браузера, а в результате автозаполнение поля как работало, так и работает...

Аватар пользователя divined divined 17 мая 2012 в 13:26

Есть такая штука в друпале:

Drupal.behaviors.ahahCallback = function() {
        jQuery(document).ajaxComplete(function(e, xhr, settings) {
                if(!ahahCallback.i) {
                        ahahCallback.i = true;
                        alert(settings.url); //урл коллбэка
                }
        }
}

Это позволить добавить код после выполнения ahah колбэка, проверьте его.

Аватар пользователя vicccy vicccy 11 июля 2012 в 15:53

расскажите пожалуйста, что в результате получилось и каким образом. Очень нужно сделать то же самое.

Аватар пользователя STINGER STINGER 2 августа 2012 в 15:27

vicccy wrote:
расскажите пожалуйста, что в результате получилось и каким образом. Очень нужно сделать то же самое.

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