Продолжаем мучить ту же тему, вскрываются истоки проблемы.
Обычная форма с двумя полями - второе поле зависит от первого.
Нужно то же самое. Проверить некие значения на сервере через аякс, если не подходят - вывести окно, если подходит - сделать редирект.
Загвоздка в валидации полей
<?php public function buildForm(array $form, FormStateInterface $form_state) {
$form['system_messages'] = [
'#markup' => '<div id="form-system-messages"></div>',
'#weight' => -100,
];
$form['type'] = array(
'#type' => 'select',
'#title' => $this->t('Type'),
'#options' => array (1 =>'first', 2 => 'second')
);
$form['second_field'] = array(
'#type' => 'textfield',
'#title' => $this->t('Second field'),
'#states' => array(
'visible' => array(
':input[name="type"]' => array('value' => 2),
),
'required' => array(
':input[name="type"]' => array('value' => 2),
)
),
// '#required' => TRUE,
);
$form['submit'] = [
'#type' => 'submit',
'#value' => 'Submit this form',
'#ajax' => [
'callback' => '::ajaxSubmitCallback',
'event' => 'click',
],
];
return $form;
}
public function ajaxSubmitCallback(array &$form, FormStateInterface $form_state) {
$response = new AjaxResponse();
$errors = drupal_get_messages();
$message = [
'#theme' => 'status_messages',
'#message_list' => $errors,
'#status_headings' => [
'error' => t('Error message'),
],
];
$messages = \Drupal::service('renderer')->render($message);
$response->addCommand(new HtmlCommand('#form-system-messages', $messages));
$all_bad= functionValidate(); // тут некая функция для проверки
if ($all_bad) {
$content['#markup'] = "NO, wrong"; $content['#attached']['library'][] = 'core/drupal.dialog.ajax';
$response->addCommand(new OpenModalDialogCommand('', $content, ['width' => '270', 'height' => '145']));
}
else {
if (count($errors['error']) == 0) $response->addCommand(new RedirectCommand('myurl'));
}
return $response;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_set_message('Form submitted!');
}?>
Если оставлять states - поле second_field не проверяется на пустое значение. Если же добавить стандартное '#required' => TRUE - проверяет, но тогда не дает отправить форму, когда выбрано first.
Как такое лечить? Вроде все сделано drupal-way.
Может кто сталкивался с рецептом лечения проблемы в англоязычной сети? А никак не могу найти конкрентно эту ситуацию
Комментарии
Один очень уважаемый, потому как очень компетентный в IT-отрасли, товарищ, про некий фреймворк сказал:
Для Drupal, особенно для Drupal 8 - это "высказывание" тоже подходит.
Опишите по подробнее суть того, что Вы хотите сделать, и 99% - Вам подскажут правильный подход и помогут советами с реализацией.
ЗЫ. Жалко на Вас смотреть, как Вы мучаетесь-)
Была готовая форма, где все работает, все поля проверяются на required.
Надо добавить новый функционал - при нажатии кнопки Submit выбранные значения в форме проверять на сервере, и возвращать true или false. Проверяем через ajax-callback, возвращаем. Есkb FALSE - значит остаемся на месте, выводим диалог-окно, все ок тут.
Если же возвращает true- надо оставить все как было - то есть проверка полей на валидацию( все работало без аякса), и редирект на другой адрес
Проблема выясняется со states - при ajax-callback тупо не идет стандартная проверка. Что и показывает эта упрощенная форма.
Что делать? От states отказаться не выйдет, может как то вместо ajax-callback как-то можно?
короче нужно как-то проверить через запрос на сервер введеные поля, и если вернет true - чтобы все было как раньше, как будто этой проверки не было.
А если false - окно с ошибкой и никуда не отправлять форму.
Загвоздка - в стандартной валидации элементов формы
Несколько раз сталкивался со states в друпал. И на 7 и на 8 версиях. Всегда есть вероятность порядка 50%, что эта хрень не будет работать. И всегда есть проверенный способ приаттачить к форме свой js и сделать там всё, что нужно.
Вместо states? В реальной форме около 10 подобных states в разных вариациях - не вариант отказываться от них.
Может ajax-callback как-то можно заменить?
Если я все правильно понял, зачем обязательным условием является использования ajax - это предварительная (перед сабмитом) валидация формы с выводом пользователю информативных сообщений (в всплывающих окошках и т.п.).
Еще что я понял, необходимо проверять "заполненность" обязательных полей, "обязательность" которых зависит от значений других полей на форме.
Т.е. грубо говоря проверка простая: если "поле 1" имеет "значение 1" то "поле 2" обязано быть заполненным.
и если "проверка" не прошла, показываем пользователю сообщение в модальном окне .
короче, очевидно, что в данном случае сервер напрягать не обязательно, все необходимые данные для валидации есть на клиенте.
Следовательно как-то само-собой напрашивается проводить валидацию полей на клиенте.
т.е. по нажатию кнопки Сабмит, проверяем поля на клиенте, и если все нормально отправляем форму на сервер для стандартного сабмита (без аякса) и далее по сценарию (редиректы-шмадиректы и т.п.)
Тут буквально в последних топиках проскакивал коммент про модуль валидации на клиенте.
Возможно даже его будет достаточно.
Если нет, ничто не мешает разобраться с валидацией на клиенте javascript-ом и jquery..
А если месье знает толк в извращениях, то как было предложено в предыдущих топиках по этой теме, наверное можно и с vue.js разобраться и т.п.-)
Использую вместо state ajax callback в том числе на event
Нет, обязательно. Мы от введенных значений проверяем на сервере другие ноды и их параметры. Было бы необязательном - проблем бы не было
И откуда я мог это знать?-)
Вы писали только про requred ..
Не у одного у Вас такая проблема: https://www.drupal.org/project/drupal/issues/2855139 ..
в последнем комменте предложено временное решение.
Но можно костыль покрасившее прилепить..
попробуйте в buildForm из form_state вытащить input
$input = $form_state->getUserInput();
при первой загрузке формы он должен быть пустыми, при аякс-сабмите и т.п. в нем будут введенные пользователем данные.
И на основании этих данных установите #required для нужных элементов формы:
<?php
$form['second_field'] = array(
$input = $form_state->getUserInput();
'#type' => 'textfield',
'#title' => $this->t('Second field'),
............
),
'#required' => isset($input['type']) && $input['type']===2,
); ?>
тогда поле должно будет проверяться на обязательность стандартным валидатором..