We have a form that includes a React JS frontend component. The component collects some required information, which the React component then supplies to the backend by populating a hidden form field.
To ensure that a user cannot bypass entering the required data through the component, we need to satisfy the following requirements:
- Before the React component loads, the "Submit" button needs to be disabled. This ensures that a user can't submit the form just by disabling JS or just clicking the button before the page finishes loading.
- After the React component loads, any time that the required values get cleared, the "Submit" button needs to be disabled.
- Once the required values are supplied, the "Submit" button should be enabled.
- It must not be possible to submit the form if the hidden value is empty.
I've tried rendering the form like this:
public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$form['selected_values'] = [
'#type' => 'hidden',
];
$form['actions'] = [
'#type' => 'actions',
'#weight' => 100,
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#button_type' => 'primary',
'#disabled' => TRUE, // Controlled by JS on the frontend
];
return $form;
}
And then in JavaScript, I have an onValueChange()
event callback that looks like this:
function onValueChange(value) {
if (value.trim() === '') {
$(submitButton).prop('disabled', true);
}
else {
$(submitButton)
.prop('disabled', false)
.removeClass('is-disabled');
}
}
I also tried:
public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$selected_values = form_state->getValue('selected_values');
$form['selected_values'] = [
'#type' => 'hidden',
];
$form['actions'] = [
'#type' => 'actions',
'#weight' => 100,
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#button_type' => 'primary',
'#disabled' => !empty($selected_values),
];
return $form;
}
Both of these approaches demonstrate the same problem -- clicking the "Submit" doesn't submit the form; it just seems to rebuild the form. With the second approach, it looks like the incoming selected values are always empty during the form render; they don't get applied to the form state until after the form is constructed.
How can we ensure that the "Submit" button starts out disabled, while requiring the necessary values?