Несовместимость states required и ajax-callback validate

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

Аватар пользователя remmor remmor 28 ноября 2018 в 11:17

Продолжаем мучить ту же тему, вскрываются истоки проблемы.
Обычная форма с двумя полями - второе поле зависит от первого.
Нужно то же самое. Проверить некие значения на сервере через аякс, если не подходят - вывести окно, если подходит - сделать редирект.
Загвоздка в валидации полей

<?php   public function buildForm(array $formFormStateInterface $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 (=>'first'=> '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 &$formFormStateInterface $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_badfunctionValidate();    // тут некая функция для проверки
   
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 &$formFormStateInterface $form_state) {
    
parent::validateForm($form$form_state);
 }
 public function 
submitForm(array &$formFormStateInterface $form_state) {
    
drupal_set_message('Form submitted!');
  }
?>

Если оставлять states - поле second_field не проверяется на пустое значение. Если же добавить стандартное '#required' => TRUE - проверяет, но тогда не дает отправить форму, когда выбрано first.
Как такое лечить? Вроде все сделано drupal-way.
Может кто сталкивался с рецептом лечения проблемы в англоязычной сети? А никак не могу найти конкрентно эту ситуацию

Комментарии

Аватар пользователя Orion76 Orion76 28 ноября 2018 в 11:51
1

Один очень уважаемый, потому как очень компетентный в IT-отрасли, товарищ, про некий фреймворк сказал:

Если то, что вы делаете на %FrameworkName% слишком сложно, значит вы что-то делаете неправильно.(с)

Для Drupal, особенно для Drupal 8 - это "высказывание" тоже подходит.

Опишите по подробнее суть того, что Вы хотите сделать, и 99% - Вам подскажут правильный подход и помогут советами с реализацией.

ЗЫ. Жалко на Вас смотреть, как Вы мучаетесь-)

Аватар пользователя remmor remmor 28 ноября 2018 в 12:05

Была готовая форма, где все работает, все поля проверяются на required.
Надо добавить новый функционал - при нажатии кнопки Submit выбранные значения в форме проверять на сервере, и возвращать true или false. Проверяем через ajax-callback, возвращаем. Есkb FALSE - значит остаемся на месте, выводим диалог-окно, все ок тут.
Если же возвращает true- надо оставить все как было - то есть проверка полей на валидацию( все работало без аякса), и редирект на другой адрес
Проблема выясняется со states - при ajax-callback тупо не идет стандартная проверка. Что и показывает эта упрощенная форма.

Что делать? От states отказаться не выйдет, может как то вместо ajax-callback как-то можно?

Аватар пользователя remmor remmor 28 ноября 2018 в 12:08

короче нужно как-то проверить через запрос на сервер введеные поля, и если вернет true - чтобы все было как раньше, как будто этой проверки не было.
А если false - окно с ошибкой и никуда не отправлять форму.

Загвоздка - в стандартной валидации элементов формы

Аватар пользователя gun_dose gun_dose 28 ноября 2018 в 12:01

Несколько раз сталкивался со states в друпал. И на 7 и на 8 версиях. Всегда есть вероятность порядка 50%, что эта хрень не будет работать. И всегда есть проверенный способ приаттачить к форме свой js и сделать там всё, что нужно.

Аватар пользователя remmor remmor 28 ноября 2018 в 12:03

Вместо states? В реальной форме около 10 подобных states в разных вариациях - не вариант отказываться от них.
Может ajax-callback как-то можно заменить?

Аватар пользователя Orion76 Orion76 28 ноября 2018 в 20:28

Если я все правильно понял, зачем обязательным условием является использования ajax - это предварительная (перед сабмитом) валидация формы с выводом пользователю информативных сообщений (в всплывающих окошках и т.п.).

Еще что я понял, необходимо проверять "заполненность" обязательных полей, "обязательность" которых зависит от значений других полей на форме.

Т.е. грубо говоря проверка простая: если "поле 1" имеет "значение 1" то "поле 2" обязано быть заполненным.

и если "проверка" не прошла, показываем пользователю сообщение в модальном окне .

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

Следовательно как-то само-собой напрашивается проводить валидацию полей на клиенте.

т.е. по нажатию кнопки Сабмит, проверяем поля на клиенте, и если все нормально отправляем форму на сервер для стандартного сабмита (без аякса) и далее по сценарию (редиректы-шмадиректы и т.п.)

Тут буквально в последних топиках проскакивал коммент про модуль валидации на клиенте.
Возможно даже его будет достаточно.
Если нет, ничто не мешает разобраться с валидацией на клиенте javascript-ом и jquery..

А если месье знает толк в извращениях, то как было предложено в предыдущих топиках по этой теме, наверное можно и с vue.js разобраться и т.п.-)

Аватар пользователя remmor remmor 30 ноября 2018 в 16:56

Orion76 wrote:

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

Нет, обязательно. Мы от введенных значений проверяем на сервере другие ноды и их параметры. Было бы необязательном - проблем бы не было

Аватар пользователя Orion76 Orion76 30 ноября 2018 в 18:06

Но можно костыль покрасившее прилепить..

попробуйте в buildForm из form_state вытащить input
$input = $form_state->getUserInput();

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

И на основании этих данных установите #required для нужных элементов формы:

<?php
$input 
$form_state->getUserInput();

   

$form['second_field'] = array(
      
'#type' => 'textfield',
      
'#title' => $this->t('Second field'),
   ............
       ),
     
'#required' => isset($input['type']) && $input['type']===2,
    );

?>

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