0

The submit element on my form uses an ajax callback which sends out an email.

I have a validation callback which I've added to this form, but it gets run after the ajax callback and so the email will be sent out even if the form doesn't validate.

I can't add the validation to the ajax callback itself because it gets used on lots of other forms on my site.

Is there any way to run my validation callback before ajax is run?

1

Actually, you will pass through your validateForm() method, whether you are using Ajax or not.

In the validateForm(), you have to set the appropriate errors on your fields which do not validate. Then, as Charles Bamford stated, you need to handle the error management in your submit callback.

So basically, you would end up with some kind of the following structure:

public function buildForm(array $form, FormStateInterface $form_state) {
  $form['#prefix'] = '<div id="my-ajax-target-element"></div>

  $form['my_field'] = [
    '#type' => 'textfield',
    '#title' => $this->t('My field title'),
  ];
  $form['submit'] = [
    '#type' => 'submit',
    '#value' => $this->t('Submit'),
    '#ajax' => [
      'callback' => '::myAjaxCallback',
      'wrapper' => 'my-ajax-target-element',
      'method' => 'replace',
    ],
 ];

 return $form;

}

public function validateForm(array &$form, FormStateInterface $form_state) {
  $values = $form_state->getValues();
  // I set error on my field here, but due to Ajax, the display
  // of error messages will be handled in the Ajax callback
  if($values['my_field'] != 'my expected value') {
    $form_state->setErrorByName('my_field', $this->t('This is my error message'));
  }
}

public function myAjaxCallback(array &$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  // If $form_state contains errors, populate the ajaxResponse content with the error messages
  if($form_state->hasAnyErrors()) {
    $errors = $form_state->getErrors();
    $command_content = $errors['my_field'];
  }
  else {
    // Happily proceed to the submission of your form
  }

  $response->addCommand(new HtmlCommand('#my-ajax-target-element', $command_content));
  return $response;
}
0

If the validation callback is not being called, you can call it manually at the top of the ajax callback with $callback($form, $form_state).

That said, the validation is probably being called, but the ajax callback doesn't know how to handle it. This is how I'm handling ajax callbacks on some forms I have.

At the top of the ajax callback:

$messages = \Drupal::messenger()->messagesByType('error');
if ($form_state->hasAnyErrors() || !empty($messages)) {
  // If the form has errors, reload it.
  $response = new AjaxResponse();
  $response->addCommand(new ReplaceCommand($css_form_id, $form));
  return $response;
}

This checks for any validation errors, and reloads the form. My form also has a status messages element at the top

$form['status_messages'] = [
  '#type' => 'status_messages',
  '#weight' => -100,
];

So that when it is reloaded, the status messages appear on it.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.