Score:0

Use AJAX On Node Add Form To Change Field Required Status

gf flag

On a node/add form I have a pair of fields that need to be able to control one another. The first field allows a user to enter a birthdate, the second field allows the user to say the birthdate is unknown.

I have attempted to work with Conditional Fields to make this work but I think for my case AJAX would be better.

If the birthdate_unkown field is not checked then the birthdate field should be required. When the birthdate_unkown field is checked then I would like to be able to make it so that the field is no longer required.

I have a working AJAX callback function I just cannot figure out how to use AJAX to change if the field is required or not.

I have tried options like:

$response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','attr',['required', false]));

or

$response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','removeAttr',['required']));

I have this code in a function that looks like this:

function _custom_field_unknown_birthday_logic(&$form, FormStateInterface $form_state) {
    \Drupal::logger('custom')->error('Unknown Birthday Callback');
    $values = $form_state->getValues();
    $unknown_birthdate = $values['field_unknown_birthdate']['value'];
    \Drupal::logger('custom')->error('Unknown Birthday Callback Value '. $unknown_birthdate);

    $response = new AjaxResponse();
    if ($unknown_birthdate == false) {
        $response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','attr',['required']));
        \Drupal::logger('custom')->error('Birthdate IS required');
    } else if ($unknown_birthdate == true) {
        $response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','removeAttr',['required'] ));
        \Drupal::logger('custom')->error('Birthdate IS NOT required');
    } else {
        \Drupal::logger('custom')->error('No Change to Birthdate');
    }
    return $response;
}

With the extensive logging I am doing I can see that I am getting to the right places in the code to issue the AJAX commands. That said the AJAX commands do not appear to change anything. I do not see anything in the console for Dev Tools either.

Any help on figuring out how to do this with AJAX is greatly appreciated. Once I get this working with AJAX there is more that needs to be accomplished that will not work with just States API.

Thanks!

id flag
Please show more of your code.
Drupal Learner avatar
gf flag
@cilefen, I have added more code. If you are able to help I would greatly appreciate it.
Jaypan avatar
de flag
Is `_custom_field_unknown_birthday_logic()` an #ajax callback? And what version of Drupal is this?
Drupal Learner avatar
gf flag
@Jaypan, yes _custom_field_unknown_birthday_logic() is the callback. I am in Drupal 9. Thanks!
Score:1
de flag

Changes to the form must be made in the form definition, and cannot be made in the ajax callback, as Drupal has already cached the form by the point of the ajax callback, so even if you figured out a way to remove the required attribute on the field in the ajax callback, Drupal would reject a missing value as the form cache from before the ajax callback will still have the form field marked as required.

Instead, in your form definition (not the #ajax callback), you likely want some version of this:

if ($form_state->getValue('field_unknown_birthdate')) {
  unset($form['field_birthday_value']['widget']['#required']);
}

Note that I am guessing the location of the #required key, as well as the field names, so you'll have to inspect the actual $form object to determine the array in which the #required key is set, and unset it.

Drupal Learner avatar
gf flag
Thank you for this response. The reason I was trying to use AJAX is because if I put this in the form alter it will not "know" that the value changed in the Boolean field. Where can I put this so that Drupal will be "aware" of the code . I also tried putting it in a custom submit handler that did not work. thanks!
Jaypan avatar
de flag
Form alter hooks are called on ajax rebuilds, so the value of the field IS known when the alter hook is called as the form is rebuilt. So you put this in your form alter hook.
Drupal Learner avatar
gf flag
thank you continuing to help. I am sorry if I am missing something obvious here. If I am not changing the required status of the field then I do not necessarily need have an AJAX callback. I am familiar with $form_state->setRebuild() in custom forms. I am not sure how I would do that with in this case? Should I call an AJAX function and just return nothing? Thanks for the clarification.
Jaypan avatar
de flag
I thought the whole point is that you want to change the required status. I'm confused.
Drupal Learner avatar
gf flag
Jaypan, yes that is the whole point. I am not sure where to put the code you recommended so that when the value of Boolean field changes your recommendation will run. My understanding was that you said that the hook_form_alter I am using would be a good place to put it because the form would be rebuilt. I think for the form to be rebuilt I need an AJAX event. I tried just returning an empty response to test and that did not run the code you suggested. I am looking to better understand where I should put this code so that it will be executed when the field changes. Thank you!
Jaypan avatar
de flag
I think maybe you should read up on how #ajax form rebuilds work - the form alter hook is called when the form is first built, and also on every ajax rebuild. So you will put that code in the form alter hook, and in the ajax callback, you return the form element that has changed to required/not required. And the code I gave will run different the first time it is run, than on ajax rebuilds, because the first time there will be no value.
Drupal Learner avatar
gf flag
thank you for all your help I got it working. I ended up needing to return some AJAX too so the form refreshes and my other code runs. Thanks!
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.