0

I'm defining an ajax form in my custom module (#ajax for submit). It is shown in custom block. But it works fine only on cache clear (on Drupal clear all caches or on ctrl+r in chrome). If I just use a link in navbar to navigate to another page or insert an url to browser my ajax callback stops being used. If I ctrl+r it starts working. I thought it's a cache issue but any cache disabling (form or block) doesn't take an effect. Please help.

UPD:

Here is the code for the form:

public function buildForm(array $form, FormStateInterface $form_state) {

    // Add a wrapper div that will be used by the Form API to update the form using AJAX
    $form['#prefix'] = '<div id="my_ajax_form">';
    $form['#suffix'] = '</div>';
    $form['#disable_inline_form_errors_summary'] = TRUE;
    $form['#cache'] = ['max-age' => 0];
    $form['#cache']['contexts'][] = 'session';

    $form['left'] = [
        '#type' => 'fieldset',
        '#prefix' => '<div class="group-left">',
        '#suffix' => '</div>',
    ];
    $form['left']['image'] = [
        '#type' => 'item',
        '#markup' => '<img src="some img url" 
            class="my-form-image" alt="image">',
    ];

    $form['right'] = [
        '#type' => 'fieldset',
        '#prefix' => '<div class="group-right">',
        '#suffix' => '</div>',
    ];
    $form['right']['headline'] = [
        '#type' => 'item',
        '#markup' => $this->t('some text1'),
    ];
    $form['right']['description'] = [
        '#type' => 'item',
        '#markup' => $this->t('some text2'),
    ];
    $form['right']['first_name'] = [
        '#type' => 'textfield',
        '#title' => $this->t('First Name'),
    ];
    $form['right']['last_name'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Last Name'),
    ];
    $form['right']['email'] = [
        '#type' => 'email',
        '#title' => $this->t('Email address'),
    ];
    $form['right']['cta'] = [
        '#type' => 'item',
        '#markup' => $this->t('some text3'),
    ];
    $form['right']['actions'] = [
        '#type' => 'actions',
    ];
    // Add a submit button that handles the submission of the form.
    $form['right']['actions']['submit'] = [
        '#type' => 'submit',
        '#value' => $this->t('SUBMIT'),
        '#attributes' => [
            'class' => [
                'myCustomBehavior',
            ]
        ],
        '#ajax' => [
            'wrapper' => 'my_ajax_form',
            'callback' => '::submitCallback',
            'event' => 'click',
            'progress' => [
                'type' => 'none',
            ],
        ],
    ];

    return $form;
}

/**
 * Validate the title and the checkbox of the form
 *
 * @param array $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *
 */
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);

    $first_name = $form_state->getValue('first_name');
    if (empty($first_name)) {
        // Set an error for the form element with a key of "first_name".
        $form_state->setErrorByName('first_name', $this->t('Please enter your first name'));
    }

    $last_name = $form_state->getValue('last_name');
    if (empty($last_name)){
        // Set an error for the form element with a key of "last_name".
        $form_state->setErrorByName('last_name', $this->t('Please enter your last name'));
    }

    $email = $form_state->getValue('email');
    if (empty($email)){
        // Set an error for the form element with a key of "email".
        $form_state->setErrorByName('email', $this->t('Please enter your email'));
    }
    else {
        $connection = \Drupal::database();
        $query = $connection->select('my_table', 'm')
            ->condition('m.email', $email, '=')
            ->fields('m', ['email']);
        $count = $query->countQuery()->execute()->fetchField();
        if (0 != $count) {
            $form_state->setErrorByName('email', $this->t('This email already exists.'));
        }
    }
}

/**
 * Form submission handler.
 *
 * @param array $form
 *   An associative array containing the structure of the form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
    $field = $form_state->getValues();
    $field_arr = [
        'first_name' => $field['first_name'],
        'last_name' => $field['last_name'],
        'email' => $field['email'],
    ];
    $query = \Drupal::database();
    $query->insert('my_table')
        ->fields($field_arr)
        ->execute();
    $form_state->setRebuild(TRUE);
}

/**
 *  Ajax callback for the form submit
 */
public function submitCallback(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    if (!$form_state->hasAnyErrors()) {
        $form['right']['#prefix'] = '<div class="group-right group-right-processed">';
        $form['right']['headline']['#markup'] = $this->t('<h1 class="my-form-headline">thank you</h1>');
        $form['right']['description']['#markup'] = $this->t('some text4');
        unset($form['right']['first_name'], $form['right']['last_name'], $form['right']['email'], $form['right']['cta'], $form['right']['actions']);
        $response->addCommand(new ReplaceCommand(NULL , $form));

        return $response;
    }
    else {
        $form_state->setRebuild();
        return $form;
    }
}

Here is the code for the block:

public function build() {
    $form = \Drupal::formBuilder()->getForm('Drupal\my_module\Form\MyForm');
    return $form;
}

public function getCacheMaxAge() {
    return 0;
}
4
  • 2
    I think it might be helpful if you included your form code in the question. It may have something to do with the way you implemented AJAX. Sep 27, 2019 at 14:42
  • @IsaiahNixon I updated my question. Thanks for the comment. Sep 28, 2019 at 15:41
  • Do you have more than one AJAX enabled form on the page? If you do, you will need to give each form unique submit IDs.
    – Kevin
    Sep 28, 2019 at 15:48
  • I've just tried on 404 page (where i don't have any other ajax forms) and ajax works only after ctrl+r. Sep 28, 2019 at 16:00

1 Answer 1

2

Actually, @Kevin was almost right. There was the search form that does not use AJAX but somehow Drupal gave the same id to both submit buttons (it was edit-submit--2. Is it a Drupal core bug?). So I had to gave custom id to my submit button and now it works fine.

1
  • I have a simular problem with private messages form. Sometimes AJAX stops working. In this case there are tow buttons with same id "edit-submit" Maybe this is a core bug. Are there any further issues on drupal.org about this problem? How can I solve this problem? It appears sometimes and nobody know when. So it should be solved. Thanx
    – drupalfan
    Jun 25, 2021 at 16:45

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.