4

I have a Drupal form that should submit via AJAX. I want to validate the input is correct. A few things are happening:

  • The validateForm method is being hit
  • I'm not able to see the errors in the form with getErrors
  • I want to validate the input, and if an error occurs, flash a message in the form that it is invalid
  • On success, I want to replace the form with a success message (but its not getting that far)

Here is my form code:

<?php

namespace Drupal\harlib_newsletter_signup\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Class NewsletterSignup.
 */
class NewsletterSignup extends FormBase {

  public $uniqueIdentifier = 'no_tagline';

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'newsletter_signup_' . $this->uniqueIdentifier;
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    if ($this->uniqueIdentifier == "with_tagline") {
      $show_tagline = TRUE;
    }
    else {
      $show_tagline = FALSE;
    }

    $wrapper = 'ajax-wrapper-' . $this->uniqueIdentifier;

    $form['#prefix'] = '<section class="hl__single-input-form"><div id="' . $wrapper . '">';
    $form['#suffix'] = '</div></section>';

    $form['#attributes']['class'][] = 'hl__single-input-form__form';
    $form['#attributes']['novalidate'] = 'novalidate';

    $form['title'] = [
      '#type' => 'label',
      '#for' => 'edit-email-address',
      '#title' => 'Stay in the know',
      '#attributes' => [
        'class' => [
          'hl__label',
          'hl__label--inline',
        ],
      ],
    ];

    if ($show_tagline) {
      $form['tagline'] = [
        '#markup' => '<div class="hl__single-input-form__helper-text">Sign up for email updates from MySite</div>',
      ];
    }

    $errors = $form_state->getErrors();

    if ($errors = $form_state->getErrors()) {
      $form['errors'] = [
        '#markup' => $errors['email_address'],
      ];
    }

    $form['email_address'] = [
      '#type' => 'email',
      '#size' => NULL,
      '#required' => TRUE,
      '#attributes' => [
        'placeholder' => $this->t('Email'),
        'class' => [
          'hl__input',
          'hl__input--inline',
          'js-is-required',
        ],
        'data-twig-suggestion' => 'newsletter_signup_email',
      ],
      '#prefix' => '<div class="hl__single-input-form__input-group">',
    ];

    $form['submit'] = [
      '#type' => 'button',
      '#value' => $this->t('Sign up'),
      '#submit' => ['::submitForm'],
      '#attributes' => [
        'class' => [
          'hl__button',
          'hl__button--small',
          'hl__button--inline',
        ],
        'data-twig-suggestion' => 'newsletter_signup_submit',
      ],
      '#suffix' => '</div>',
      '#ajax' => [
        'wrapper' => $wrapper,
        'method' => 'replace',
        'callback' => '::ajaxRebuildForm',
        'progress' => [
          '#type' => 'none',
        ],
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $email_value = $form_state->getValue('email_address');

    if (empty($email_value) || !\Drupal::service('email.validator')->isValid($email_value)) {
      $form_state->setError($form['email_address'], $this->t('Please enter a valid email address.'));
    }

    if (mailchimp_is_subscribed('XXXXXXX', $email_value, TRUE)) {
      $form_state->setError($form['email_address'], $this->t('You are already subscribed to our newsletter.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $result = mailchimp_subscribe('XXXXXXX', $form_state->getValue('email_address'));

    if (empty($result)) {
      $form_state->setError($form['email_address'], $this->t('You are already subscribed to our newsletter.'));
    }
    else {
      drupal_set_message($this->t('Thank you for subscribing to our newsletter!'));
    }
  }

  public function ajaxRebuildForm(array $form, FormStateInterface $formState) {
    return $form;
  }

}

Is ajaxRebuildForm necessary? How can I validate this? Is setError still workable in an ajax submit?

EDIT: I've updated the validateForm method to use AjaxResponse. Nothing is happening on my screen.

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $email_value = $form_state->getValue('email_address');

    if (empty($email_value) || !\Drupal::service('email.validator')->isValid($email_value)) {
      //$form_state->setError($form['email_address'], $this->t('Please enter a valid email address.'));
      //$form_state->setRebuild();
      $response->addCommand(new CssCommand('.hl__single-input-form__input-group', ['border' => '3px solid red']));
      $response->addCommand(new AlertCommand('Heyoooo'));
      return $response;
    }

    if (mailchimp_is_subscribed('XXXXXXX', $email_value, TRUE)) {
      $form_state->setError($form['email_address'], $this->t('You are already subscribed to our newsletter.'));
    }
  }
1
  • Just a note, if you had used a randomized wrapper ID like 'ajax-wrapper-' . uniqid(), it wouldn't work as subsequent builds/submits would have different wrapper IDs.
    – mbomb007
    Commented Mar 13, 2023 at 20:46

2 Answers 2

2
+100

This actually turned out to be a combination of a few things:

  1. I was using this form more than once on the same page
  2. It is an AJAX form, so the submit needed to be unique.

Adding:

$form['submit_' . $this->uniqueIdentifier] instead of $form['submit'] resolved the issue. I now get AJAX errors on both, and both submit correctly.

0

It's probably mailchimp_is_subscribed that is breaking it. I tried the code myself with a slight change:

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $email_value = $form_state->getValue('email_address');

    if (empty($email_value) || !\Drupal::service('email.validator')->isValid($email_value)) {
      $form_state->setError($form['email_address'], $this->t('Please enter a valid email address.'));
    }

    else {
      if (mailchimp_is_subscribed('XXXXXXX', $email_value, TRUE)) {
        $form_state->setError($form['email_address'], $this->t('You are already subscribed to our newsletter.'));
      }
    }
  }

screen-shot

If this does not change the behavior on your system, change the default theme and test it.

Your theme may be not printing the errors. If it does, then you might be missing the messages highlighted region from your template. Search for {{ page.highlighted }} in your theme or it's parent and make sure it's printed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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