Search code examples
drupal-8drupal-themingajaxform

Drupal - Ajax validation only works when I am connected


I am new in Drupal world and I'm trying to use the Drupal From API to create a contact form with Ajax validation.

I'm facing 2 issues:

  • My following form (see below) works well but only when the user is connected as administrator. When I am not logged in as an administrator, it does not work.

  • I also created a custom Block to display my Form, unfortunately the block does not appear when I am logged in.

I try to follow this guide whitout success: https://panshul1410.blog/2018/07/15/drupal-8-ajax-validations-for-custom-form/

Here is the form I created:

<?php

namespace Drupal\dalcom_contact\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class DalcomContactForm extends FormBase {

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

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

    // Disable caching.
    $form['#cache']['max-age'] = 0;

    // Disable browser HTML5 validation.
    $form['#attributes']['novalidate'] = 'novalidate';

    // This will generate an anchor scroll to the form when submitting.
    $form['#action'] = '#dlcm_cform';

    $form['mail_visitor'] = [
      '#type' => 'email',
      '#placeholder' => t('E-mail*'),
      '#description' => 'Your mail',
      '#required' => TRUE,
      '#ajax' => [
        'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::mailValidateCallback',
        'effect' => 'fade',
        'event' => 'change',
        'progress' => [
          'type' => 'throbber',
          'message' => NULL,
        ],
      ],
    ];

    $form['message_visitor'] = [
      '#type' => 'textarea',
      '#placeholder' => t('Message*'),
      '#description' => 'Your message',
      '#required' => TRUE,
      '#ajax' => [
        'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::messValidateCallback',
        'effect' => 'fade',
        'event' => 'change',
        'progress' => [
          'type' => 'throbber',
          'message' => NULL,
        ],
      ],
    ];

    $form['accept_box'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('I accept the CME terms of use'),
      '#required' => TRUE,
      '#ajax' => [
        'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::acceptboxalidateCallback',
        'effect' => 'fade',
        'event' => 'change',
        'progress' => [
          'type' => 'throbber',
          'message' => NULL,
        ],
      ],
    ];

    $form['candidate_copy'] = [
      '#type' => 'checkbox',
      '#title' => t('Send me a copy of my message.'),
    ];

    $form['actions']['#type'] = 'actions';

    $form['actions']['submit'] = [
      '#type' => 'button',
      '#value' => $this->t('Send'),
      '#ajax' => [
        'event' => 'click',
        'progress' => [
          'type' => 'throbber',
          'message' => 'Sending...',
        ],

      ],
    ];

    $form['#theme'] = 'dalcom_contact_theme';

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    foreach ($form_state->getValues() as $key => $value) {
      drupal_set_message($key . ': ' . $value);
    }
  }

  public function mailValidateCallback(array &$form, FormStateInterface $form_state) {
    $ajax_response = new AjaxResponse();

    if (!$form_state->getValue('mail_visitor') || empty($form_state->getValue('mail_visitor'))) {
      $text = 'No email registered';
      $color = 'red';
    }
    elseif (!filter_var($form_state->getValue('mail_visitor'), FILTER_VALIDATE_EMAIL)) {
      $text = 'Invalid email address';
      $color = 'red';
    }
    else {
      $text = 'Valid mail';
      $color = 'green';
    }

    $ajax_response->addCommand(new HtmlCommand('#edit-mail-visitor--description', $text));

    $ajax_response->addCommand(new InvokeCommand('#edit-mail-visitor--description', 'css', ['color', $color]));

    return $ajax_response;
  }

  public function messValidateCallback(array &$form, FormStateInterface $form_state) {
    $ajax_response = new AjaxResponse();

    if (!$form_state->getValue('message_visitor') || empty($form_state->getValue('message_visitor'))) {
      $text = 'No messages written';
      $color = 'red';
    }
    elseif (strlen($form_state->getValue('message_visitor')) < 6) {
      $text = 'At least 7 characters';
      $color = 'red';
    }
    else {
      $text = 'Messages written';
      $color = 'green';
    }

    $ajax_response->addCommand(new HtmlCommand('#edit-message-visitor--description', $text));

    $ajax_response->addCommand(new InvokeCommand('#edit-message-visitor--description', 'css', ['color', $color]));

    return $ajax_response;
  }

  public function acceptboxValidateCallback(array &$form, FormStateInterface $form_state) {
    $ajax_response = new AjaxResponse();

    if (empty($form_state->getValue('accept-box'))) {
      $text = 'You must accept our termes of use to continue';
      $color = 'red';
    }

    $ajax_response->addCommand(new HtmlCommand('#edit-accept-box--description', $text));

    $ajax_response->addCommand(new InvokeCommand('#edit-accept-box--description', 'css', ['color', $color]));

    return $ajax_response;
  }

}

It works very well. But Ajax validation only works when I am connected. When I am not logged in as an administrator, it does not work.

Here is the block to display the form in my footer.

<?php

namespace Drupal\dalcom_contact_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormInterface;

/**
 * Provides a 'dalcom contact' block.
 *
 * @Block(
 *   id = "dalcom_contact_block",
 *   admin_label = @Translation("Dalcom Contact Block"),
 *   category = @Translation("Block du formulaire Dalcom Contact")
 * )
 */
class DalcomContactBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $form = \Drupal::formBuilder()->getForm('\Drupal\dalcom_contact\Form\DalcomContactForm');
    return $form;
  }
}

As explain upper, the block does not appear when I am logged in. I have access to the form only through the path I defined in module.routing.yml. And when it appears (so when I'm not logged in), Ajax doesn't work on this block form either.

Does anyone have any idea what could cause this? Please help me.

Edited:

Here is the module.routing.yml file

dalcom_contact.form:
  path: '/contact-us.html'
  defaults:
    _title: 'Contact Us'
    _form: 'Drupal\dalcom_contact\Form\DalcomContactForm'
  requirements:
    _permission: 'access content'

block.info.yml

name: Dalcom Contact Block
type: module
description: Block du formulaire Dalcom Contact.
core: 8.x
package: Custom
dependencies:
- node
- block

Updated:

I notice that when the form does not appear (when I am connected), it appears in its place

 <span data-big-pipe-placeholder-id="…"></span>

I've done some research on this, but I can't get out of it. Maybe this will help you to know what's going on.


Solution

  • I finally found the solution on the Drupal forum. I put it here, maybe it will help in the future a novice who will be in my case.

    What was missing was simply a list of essential javascripts for anonymous users. It seems that at one time it wasn't necessary, but now we have to add them otherwise they wouldn't be loaded for anonymous users.

    So what I needed to do was add this to my theme.libraries.yml file

    my_scripts:
      version: VERSION
      js:
        js/scripts.js: {}
      dependencies:
        - core/jquery
        - core/drupal.ajax
        - core/drupal
        - core/drupalSettings
        - core/jquery.once