The setup:

I have a Drupal 8 form created manually, and I would like to recreate it using Webform module.

So far, I have managed to recreate everything (required fields and submission handler), but there is a last bit missing: the client-side validation that triggers on change.

The initial form have fields defined as follows:

$form['first-name'] = array(
  '#type' => 'textfield',
  '#title' => $this->t('First name'),
  '#required' => true,
  '#required_error' => $this->t('This is a required field. Please enter your first name.'),
  '#ajax' => [
    'callback' => '::validateFnameAjax',
    'effect' => 'fade',
    'event' => 'change',
    'progress' => FALSE,

Calling validation functions like this one:

public function validateFnameAjax(array &$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $errorValidation = '<div class="form-item-message form-item__error-message"><small class="text-danger"></small></div>';
  $successValidation = '<div class="form-item-message form-item__success-message"><small class="text-success"></small></div>';
  // Assert the name field has been included
  if (!$form_state->getValue('first-name') || empty($form_state->getValue('first-name'))) {
    $message = $this->t('This is a required field. Please enter your first name.');
    $response->addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'removeClass', ['is-valid']));
    $response->addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'addClass', ['is-invalid']));
    $response->addCommand(new ReplaceCommand('.js-form-item-first-name .form-item-message', $errorValidation));
    $response->addCommand(new HtmlCommand('.js-form-item-first-name .text-danger', $message));
  else {
    $message = $this->t('Your first name is valid.');
    $response->addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'removeClass', ['is-invalid']));
    $response->addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'addClass', ['is-valid']));
    $response->addCommand(new ReplaceCommand('.js-form-item-first-name .form-item-message', $successValidation));
    $response->addCommand(new HtmlCommand('.js-form-item-first-name .text-success', $message));
  return $response;

In the new webform function I have changed lines one and six, but the rest of the code is the same.

New line one:

  public function validateFnameAjax(WebformSubmissionInterface $webform_submission) {

New line 6:

  if (!$webform_submission->getElementData('first_name') || empty($webform_submission->getElementData('first_name'))) {

The challenge:

Implement the same behaviour: trigger the custom validation when the content in the field changes (before submission).

Current status:

I have tried to include the Ajax properties using the Advanced tab of the edit field UI as you can see in the following screenshots:

enter image description here

enter image description here

But I get this error in the log:

Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse() (line 67 of /var/www/drupalvm/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php).

Does anyone know what am I doing wrong to get this error, and how to make this client side validation work?


Although this answer does not provide the solution to add custom client-side validation to a Webform field using advanced custom properties, it provides a working alternative to add client-side validation to a Webform field.

Given that Webform UI comes with the option to add custom CSS and Javascript to a Webform, I have made use of this option to add my custom validation.

enter image description here

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.