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
    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. Oct 19, 2022 at 0:29
  • No, in submitForm() - that's your only submit handler.
    – Jaypan
    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. 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. Oct 28, 2022 at 22:43

0

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.