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:
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?