0

Building a custom module in Drupal 9.4.5. I need to have the user to select a country from one form select, and that would populate a second (states/provinces) using a form AJAX callback.

screenshot of form selects

It works perfectly when I'm logged in as the admin, but when I log out, I get this error message when I attempt to select a country.

An error occurred while attempting to process /mem?ajax_form=1&_wrapper_format=drupal_ajax: ajax.$form.ajaxSubmit is not a function

This is the module I wrote.

qmem.libraries.yml

qmem_lib:
  version: VERSION
  dependencies:
    - core/jquery
    - core/drupal.ajax

qmem.routing.yml

qmem.content:
  path: '/mem'
  defaults:
    _controller: '\Drupal\qmem\Controller\QMemController::content'
    _title: 'QM Member List'
  requirements:
    _permission: 'access content'

qmem/src/Controller/QMemController.php

namespace Drupal\qmem\Controller;

use Drupal\Core\Controller\ControllerBase;

class QMemController extends ControllerBase {
  public function content() {
    $output['form'] =  \Drupal::formBuilder()->getForm('\Drupal\qmem\Form\QMemFilters');
    $output['#attached']['library'][] = 'qmem/qmem_lib';
    
    // going to add a bunch of other stuff here later
    return $output;
  }
}

qmem/src/Form/QMemFilters.php

namespace Drupal\qmem\Form;

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

/**
 * Form that displays the filters for the courses page
 */
class QMemFilters extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'qmem_filters_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $country_opts = [
      0 => '- Any -',
      "United--States" => "United States",
      "Canada" => "Canada",
      "Mexico" => "Mexico",
      ];

    if (empty($form_state->getValue('country'))) {
      $selected_country = 0;
    } else {
      // Get the value if it already exists.
      $selected_country = $form_state->getValue('country');
    }
    $form['country'] = array(
      '#type' => 'select',
      '#title' => $this->t('Country'),
      '#default_value' => $selected_country,
      '#options' => $country_opts,
      '#prefix' => '<div class="columns large-3">',
      '#suffix' => '</div>',
      '#ajax' => [
        'callback' => '::get_state_selector',
        'wrapper' => 'states-container',
        'event' => 'change'
        ],
    );

    // When the form is rebuilt during ajax processing, the $selected_country
    // variable will now have the new value and so the options will change.

    $form['state_province'] = [
      '#type' => 'select',
      '#prefix' => '<div id="states-container" class="columns large-3">',
      '#suffix' => '</div>',
      '#title' => $this->t('State/Province/Territory'),
      '#options' => static::get_states($selected_country),
      '#default_value' => !empty($form_state->getValue('state_province')) ? $form_state->getValue('state_province') : '',
    ];
    return $form;
  }

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

  public static function get_state_selector(array &$form, FormStateInterface $form_state) {
    return $form['state_province'];
  }

  public static function get_states($country) {
    $states_options = array(
      '0' => '- Any -',
      'AL'=>'Alabama',
      'AK'=>'Alaska',
      'AZ'=>'Arizona',
      'AR'=>'Arkansas',
      'CA'=>'California',
      'CO'=>'Colorado',     
      );
 
    $canada_options = array(
      '0' => '- Any -',
      'AB' => "Alberta",
      'BC' => "British Columbia",
      'MB' => "Manitoba",
    );

    $mexicoStatesList = array(
      '0' => '- Any -',
      'AG' => 'AGUASCALIENTES',
      'BC' => 'BAJA CALIFORNIA',
      'BS' => 'BAJA CALIFORNIA SUR',
      'CH' => 'COAHUILA',
      'CI' => 'CHIHUAHUA',
      'CL' => 'COLIMA', 
    );

    if(!empty($country)) {
      $country = str_replace('--', ' ', $country);
    }

    $states =  [0 => '- Any -'];
    switch ($country) {
      case 'United States':
        $states = $states_options;
        break;
      case 'Canada':
        $states = $canada_options;
        break;
      case 'Mexico':
        $states = $mexicoStatesList;
        break;
    };

    return $states;
}

I've already tried adding many different dependencies into my libraries.yml file, like core/jquery.form, core/drupal, or core/drupal.form without luck.

5
  • At a glance, you need to add $form_state->setRebuild(TRUE) in the submission handler.
    – Jaypan
    Commented Oct 19, 2022 at 0:21
  • @Jaypan - into the function get_state_selector() ? That's the only submission handler being called here. I tried that but still no change. Commented Oct 19, 2022 at 0:29
  • No, in submitForm() - that's your only submit handler.
    – Jaypan
    Commented Oct 19, 2022 at 0:41
  • @jaypan submitForm() isn't being called yet is it? The callback on change (country) is get_state_selector(). I tried it just to see but no change. Commented Oct 19, 2022 at 17:12
  • After much debugging, and installing this module into a fresh Drupal 9 site, I can report that I found the problem. And the problem is not the module. This is working fine on a clean Drupal site. The issue turned out to be an unrelated javascript in our theme. Specifically we are using the Zurb Foundation library, and there was a script bundled with this called "what-input.js". This was apparently interfering with Drupal's AJAX form system. Removing it doesn't seem to cause a problem for Foundation (whew), and resolved the issue. Commented Oct 28, 2022 at 22:43

0

Your Answer

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

Browse other questions tagged or ask your own question.