2

Is it normal that my validateForm method in Form API doesn't trigger second time i call it?

And if yes, how do i trigger it multiple times? I've got multistep form and i want to validate each step individually. Would be perfect to validate steps with validateForm.

First step can be validated, but on click Next in the second step inputs are not validated anymore, it skips validateForm() method.

Buttons:

$button = [
      '#type' => 'button',
      '#value' => $this->t('Next'),
      '#attributes' => ['class' => ['btn-primary pull-right button-next']],
      '#name' => 'next_' . $callbackName,
      '#ajax' => [
        'callback' => '::ajaxCallbackValidate' . $callbackName,
        'url' => Url::fromRoute('route.name'),
        'options' => [
          'query' => [
            FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
          ],
        ],
      ],
    ];

validateForm() :

public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
    $values = $form_state->getValues();

    if ($values['validate_step'] && !empty($values['validate_step'])) {
      switch ($values['validate_step']) {
        case "personal":
          //Validate personal;
          //break;
        // Etc.

Edit : ajaxCallback methods look like that :

public function ajaxCallbackValidatepersonal(array &$form, FormStateInterface $form_state) {
   $ajaxResponse = new AjaxResponse();

    if (count($form_state->getErrors()) == 0) {
      $form['validate_step']['#value'] = "step_2";
    }
    $errors = StatusMessages::renderMessages();
    $ajaxResponse->addCommand(new PrependCommand(
        '#class-name',
        render($errors)
      )
    );

    // Here i was trying to do something with validation, doesn't work
    $form_state->setValidationComplete(FALSE);
    $form_state->setValidationEnforced(TRUE);
    $form['status']['#validated'] = FALSE;
    $form['status']['#sorted'] = False;
    
    $ajaxResponse->addCommand(
      new HtmlCommand(
        '#form_wrapper', $form
      )
    );

    $ajaxResponse->addCommand(new InvokeCommand(NULL, 'function1'));
    $ajaxResponse->addCommand(new InvokeCommand(NULL, 'function2'));

    return $ajaxResponse;
  • 1
    Does it maybe somehow set isValidated or something like that under the hood? Maybe have a look at how Webform does it in their multistep forms. – leymannx Jun 25 at 9:19
  • 1
    It looks like you're creating a switch to handle each step individually, have you tried creating separate validate callbacks for each step? – sonfd Jun 25 at 10:53
  • In $form there are multiple '#validated' => true placed everywhere. But changing it doesn't make any difference. In callback methods form_state->setErrorByName creates exception, which means that i can't set error inside callback, only if i return markup with error directly. I don't think it's a good way of doing that, validateForm() is default method for validation and i didn't find any way to replace it for every callback individually and set error inside it. – StewieSWS Jun 25 at 11:34
  • I would try adding your individual validation callbacks in buildForm when you're on the appropriate step. If you're on the personal step, add the personal callback to form validation. There's nothing wrong with adding additional validate callbacks. – sonfd Jun 25 at 12:06
  • 2
    You know you can have a #validate and #ajax at the same time? @sonfd is referring to #validate. In #ajax callbacks you can't run code on $form or $form_state. – 4k4 Jun 25 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.