Score:0

Trying to populate one form select with another using Ajax, getting ajax.$form.ajaxSubmit is not a function

cn flag

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.

Jaypan avatar
de flag
At a glance, you need to add `$form_state->setRebuild(TRUE)` in the submission handler.
cn flag
@Jaypan - into the function get_state_selector() ? That's the only submission handler being called here. I tried that but still no change.
Jaypan avatar
de flag
No, in `submitForm()` - that's your only submit handler.
cn flag
@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.
cn flag
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.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.