УрокЗаставляем любую форму выполняться через AJAX в Drupal 7

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

Создаём страницу для ajax запроса

С помощью hook_menu() создаём страницу, которая будет принимать ajax запрос из формы:

/**
 * Implements hook_menu().
 */
function ajax_forms_menu() {
  $items = array();
 
  $items['ajax_forms_ajax'] = array(
    'page callback' => 'ajax_forms_ajax_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
  );
 
 
  return $items;
}

Здесь стоит обратить внимание на delivery callback. Значение этого параметра - функция, которая будет вызывать набор результатов для страницы и отдавать её браузеру. По умолчанию это drupal_deliver_html_page(), однако в нашем случае - это ajax_deliver(), который умеет коррентно обрабатывать запросы и ответы ajax.

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

/**
 * Implements hook_form_alter().
 */
function ajax_forms_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'user_register_form') {
 
    // Добавляем div, куда будем ложить сообщения, в самый верх формы
    $form['messages'] = array(
      '#markup' => '<div id="ajax-forms-messages"></div>',
      '#weight' => -50,
    );
 
    // Включаем ajax для кнопки
    $form['actions']['submit']['#ajax'] = array(
      'path' => 'ajax_forms_ajax',
    );
  }
}

Пока вроде бы ничего сложного. Теперь последняя функция - непосредственно работа самого ajax'a:

/**
 * Provides ajax callback for form submit
 */
function ajax_forms_ajax_callback() {
 
  // Подключаем файл из модуля user.
  // В данной ситуации без него работать не будет, но
  // вообще он не нужен. Надо подключать только те файлы,
  // без которых форма не сможет корректно отработать.
  // Во многих случаях вообще ничего подключать не надо.
  module_load_include('pages.inc', 'user');
 
  // Получаем данные о форме и её состоянии
  list($form, $form_state) = ajax_get_form();
 
  // Заставляем выполниться все действия формы, то есть
  // выполняем все validate и submit функции для этой формы.
  drupal_process_form($form['#form_id'], $form, $form_state);
 
  // Собираем сообщения, которые вылезли в процессе выполнения формы
  $commands = array();
  $commands[] = ajax_command_html('#ajax-forms-messages', theme('status_messages'));
 
  // Записываем сообщение в div, который был добавлен вверху формы
  return array('#type' => 'ajax', '#commands' => $commands);
}

Ну вот, собственно, и всё. Все комменты в коде.

Я попробовал прикрутить это к редактированию / добавлению ноды. Заработало. Пруф:

ajax_test.png

Комментарии

Аватар пользователя Demetr
Demetr написал:

Евгений, здравствуйте. Давно читаю ваши статьи. Но очень жаль, что для Д6 перестали писать. В связи с этим вопрос - есть ли способ прикрутить этот метод для шестой версии?

05.01.2012 21:53
Аватар пользователя Spleshka
Spleshka написал:

Для шестёрки ещё проще. Скачиваете модуль ajax. После чего в хуке hook_form_alter() у формы указываете так:

$form['#ajax'] = array(
  'enabled' => TRUE
);

Всё, аякс будет работать. Более подробно можно почитать тут.

По поводу шестёрки - она устаревает. Да и работа с аяксом в семёрки на порядок выше и лучше.

05.01.2012 22:25
Аватар пользователя Demetr
Demetr написал:

Спасибо. Шестерка может и стареет, но несколько сайтов уже сделаны и переносит их на 7-ку долго. Еще раз спасибо за ответ

05.01.2012 22:40
Аватар пользователя stelk
stelk написал:

Ищу давно способ вывода формы комментариев черех quick tabs с аякс но пока безуспешно

06.01.2012 02:22
Аватар пользователя Spleshka
Spleshka написал:

Тут думать надо и кодить) Задача не совсем тривиальная, надо какое-то время потратить на неё. Сначала требуется точное тз - что и как вы хотите выводить.

06.01.2012 04:22
Аватар пользователя stelk
stelk написал:

На странице продукта выводить вкладки
(Обо всем views) (Характеристики vews) (комментарии их содержимое и форма добавления комментариев)

Все то подргружать через ajax

06.01.2012 16:22
Аватар пользователя Spleshka
Spleshka написал:

Комментарии и форма добавления комментариев - это одна вкладка, или разные?

06.01.2012 17:20
Аватар пользователя stelk
stelk написал:

Да это одна вкладка.

07.01.2012 16:39
Аватар пользователя Spleshka
Spleshka написал:

ПОнял. Это не сложно. Думаю завтра приду домой и напишу вам решение.

07.01.2012 18:39
Аватар пользователя Spleshka
Spleshka написал:

В node.tpl.php темы:

$tabs = array();
 
$tabs['first'] = array(
  'title' => 'Обо всём',
  'type' => 'view',
  'vid' => 'АЙДИ_ВЬЮХИ',
  'display' => 'ВИД_ВЬЮХИ',
  'args' => 'АРГУМЕНТЫ_ЕСЛИ_НАДО',
);
 
$tabs['second'] = array(
  'title' => 'Характеристики',
  'type' => 'view',
  'vid' => 'АЙДИ_ВЬЮХИ',
  'display' => 'ВИД_ВЬЮХИ',
  'args' => 'АРГУМЕНТЫ_ЕСЛИ_НАДО',
);
 
$tabs['third'] = array(
  'title' => 'Комментарии',
  'type' => 'freetext',
  'text' => render($content['comments']),
);
 
$quicktabs['qtid'] = 'my-quicktabs-unique-id';
$quicktabs['tabs'] = $tabs;
$quicktabs['ajax'] = TRUE;
print theme('quicktabs', $quicktabs);
08.01.2012 21:15
Аватар пользователя stelk
stelk написал:

А в 6ке наверно по сложнее ?

09.01.2012 15:56
Аватар пользователя Spleshka
Spleshka написал:

Нет, по сути тоже самое, только закидывать этот код надо в другой шаблон, вот и всё.

09.01.2012 17:41
Аватар пользователя stelk
stelk написал:

а в какой другой ?

10.01.2012 05:23
Аватар пользователя Spleshka
Spleshka написал:

в comment-wrapper.tpl.php

10.01.2012 13:45
Аватар пользователя stelk
stelk написал:

пробую.

'vid' => 'АЙДИ_ВЬЮХИ', я взял название вьюхи
'display' => 'ВИД_ВЬЮХИ', я так понял это defaults
'args' => 'АРГУМЕНТЫ_ЕСЛИ_НАДО', %1
$quicktabs['qtid'] = 'my-quicktabs-unique-id'; взял из quicktabs Machine-readable name:

вставляю весь этот код в comment-wrapper.tpl.php Но получаю ошибку

10.01.2012 18:04
Аватар пользователя Spleshka
Spleshka написал:

Покажите весь код, которым вы пытаетесь это сделать.

11.01.2012 13:52
Аватар пользователя stelk
stelk написал:
$tabs = array();
 
$tabs['first'] = array(
  'title' => 'Обо всём',
  'type' => 'view',
  'vid' => 'tab_harakteristik',
  'display' => 'Defaults',
  'args' => '%1',
);
 
$tabs['second'] = array(
  'title' => 'Характеристики',
  'type' => 'view',
  'vid' => 'tab_harakteristik',
  'display' => 'Defaults',
  'args' => '%1',
);
 
$tabs['third'] = array(
  'title' => 'Комментарии',
  'type' => 'freetext',
  'text' => render($content['comments']),
);
 
$quicktabs['qtid'] = 'tabes';
$quicktabs['tabs'] = $tabs;
$quicktabs['ajax'] = TRUE;
print theme('quicktabs', $quicktabs);
12.01.2012 01:35
Аватар пользователя Spleshka
Spleshka написал:

не 'args' => '%1', а то, что должно передаваться в качестве аргумента. Например, nid материала или что-то ещё.

12.01.2012 13:52
Аватар пользователя stelk
stelk написал:

без аргументов тоже не работает, появляются пункты если убрать

$tabs['third'] = array(
  'title' => 'Комментарии',
  'type' => 'freetext',
  'text' => render($content['comments']),

появляются пункты но пишет
You are not authorized to access this content.

12.01.2012 16:08
Аватар пользователя stelk
stelk написал:

подскажите еще какие то варианты может попробовать?

20.01.2012 12:07
Аватар пользователя Spleshka
Spleshka написал:

Вообще должно всё верно выводиться. Если вы сидите под админом, то ошибка You are not authorized to access this content. не может быть из-за ошибок доступа. Значит, что-то вы делаете несовсем правильно.

21.01.2012 13:57
Аватар пользователя stelk
stelk написал:

Могу показать на примере только нет у вас личных сообщений )

21.01.2012 18:13
Аватар пользователя Spleshka
Spleshka написал:

Зато у меня есть форма контактов)

22.01.2012 16:24
Аватар пользователя Volodymyr
Volodymyr написал:

добрый вечер, можете помочь мне? делаю для drupal 7 такую фичу, хочу чтобы форма добавления ноды выполнялась через аякс, сделал как у вас (айдишку формы поменял на свою, "reviews_node_form"), но получаю ошибку
"Возникла AJAX HTTP ошибка.
Полученный код HTTP: 200
Следует отладочная информация.
Путь: /ajax_forms_ajax
СтатусТекстом
ОтветТекстом:
Fatal error: Call to undefined function node_form_validate() in /home/xxx/xxx/xx/public_html/includes/form.inc on line 1432"

нашел эту (node_form_validate()) функцию в файле "node.pages.inc" подключал его в этой строчке module_load_include('pages.inc', 'user'); но всетаки получаю ошибку ((

20.02.2012 00:03
Аватар пользователя Spleshka
Spleshka написал:

добавьте при создании формы:

$form['#process'][] = 'reviews_form_process';

А потом где-нибудь в этом же файле:

function reviews_form_process($form) {
  module_load_include('pages.inc', 'user')
  return $form;
}
20.02.2012 21:17
Аватар пользователя Volodymyr
Volodymyr написал:

спасибо, но пока ошибка все еще есть ((
вот весь мой код:

<?php
function ajax_forms_menu() {
  $items = array();
  $items['ajax_forms_ajax'] = array(
    'page callback' => 'ajax_forms_ajax_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
  );
  return $items;}
function ajax_forms_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'reviews_node_form') {
    $form['messages'] = array(
      '#markup' => '<div id="ajax-forms-messages"></div>',
      '#weight' => -50,
    );
	$form['#process'][] = 'reviews_form_process';
    $form['actions']['submit']['#ajax'] = array(
      'path' => 'ajax_forms_ajax',
    );
  }
}
function reviews_form_process($form) {
  module_load_include('pages.inc', 'user');
  return $form;
}
function ajax_forms_ajax_callback() {
  list($form, $form_state) = ajax_get_form();
  drupal_process_form($form['#form_id'], $form, $form_state);
  $commands = array();
  $commands[] = ajax_command_html('#ajax-forms-messages', theme('status_messages'));
  return array('#type' => 'ajax', '#commands' => $commands);
}

поставил $form['#process'][] = 'reviews_form_process'; в функцию "ajax_forms_form_alter" какие еще могут быть варианты? вот http://ivyshka.vin-life.com/reviews страница, для которой я это делаю

20.02.2012 23:32
Аватар пользователя Spleshka
Spleshka написал:

Логично. Вам надо не

module_load_include('pages.inc', 'user');

а так:

module_load_include('pages.inc', 'node');

Вы же должны подключить node.pages.inc :)

21.02.2012 02:36
Аватар пользователя Volodymyr
Volodymyr написал:

большое спасибо, все работает :)
еше такой вопрос, Вы не подскажете где можно поменять сообщение которое выводиться после создания материала. Я нашел пока только вариант в переводах поменять, но такой вариант заменит сообщение для всех типов материала, а хотелось бы только для одного типа материала, может можно это сделать и в этом модуле?

21.02.2012 10:48
Аватар пользователя Иван
Иван написал:

Привет! Сделал все как написано, но форму изначально оборачиваю в fancybox:

$("a[href*='/user/register']").click(function () {
                    $.fancybox.showActivity();
                    $.get(Drupal.settings.basePath+'user/register', function (data) {
                        var form = $('#user-register-form', data);
                        $.fancybox({content:form});
                    });
                    return false;
                });

Получается при нажатии субмита все аякс не работает, страница перегружается.

25.03.2012 14:21
Аватар пользователя Иван
Иван написал:

Все, интерес к теме исчерпан?

30.03.2012 01:27
Аватар пользователя Spleshka
Spleshka написал:

После получения формы вызови Drupal.attachBehaviors();

12.04.2012 23:30
Аватар пользователя Анатолий
Анатолий написал:

Здравствуйте! А как тут же обновить страницу?

20.09.2012 20:19
Аватар пользователя Александр
Александр написал:

можно ли форму регистрации вызвать стандартными свойствами и с помощью ajax сделать валидацю без CTOOLS?

10.10.2012 13:32
Аватар пользователя Владимир_shanti
Владимир_shanti написал:

Супер, спасибо за статью. Прикрутил аякс к форме создания ноды. У меня на странице выводится несколько форм создания нод, и надо было сделать чтобы текущая форма по сабмиту скрывалась и вместо нее выводилось статусное сообщение. Сделал через добавление префикса и суффикса формы в form_alter, куда выводил уникальный id текущей формы (из $form['#id']).

05.11.2012 19:18
Аватар пользователя Сергей
Сергей написал:

Добрый день. Подскажите как реализовать следующие. Вывожу форму регистрации через ajax.
Но submit на ajax не работает

15.01.2013 16:11
Аватар пользователя Frantsuzzz
Frantsuzzz написал:

Здравствуйте. Скажите, а этим способом можно перегружать форму? как для многошаговых форм?

24.01.2013 10:12
Аватар пользователя Гость
Гость написал:

Здравствуйте!
Сделала форму для обратной связи. Скажите что добавить, что бы после отправки форма очищалась?

10.10.2013 20:08
Аватар пользователя 1
1 написал:

1

04.12.2013 12:28
Аватар пользователя Иван
Иван написал:

Подскажите, пожалуйста, как в предложенной схеме можно очищать форму поле ее успешной обработки?

21.12.2013 02:23
Аватар пользователя alfaqq
alfaqq написал:

Спасибо, работает. а можно ли после создания скрыть саму форму и оставить только сообщение об успешном создании? Да и поле типа изображение не отправляется если не нажать Закачать, баз ajax отправляется нормально

03.09.2014 18:57
Аватар пользователя vic
vic написал:

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

13.03.2015 10:23
Аватар пользователя Виктор
Виктор написал:

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

Как обновить или обнулить форму?

13.03.2015 10:33

Комментировать