0

I have 2 fields in a form. One select list and another entity reference field referring to a Paragraph type (multivalued). The on-change event should trigger an ajax callback which will disable some of the fields in the paragraph type. I managed to achieve this on ajax callback. Now, the problem is when I add more values to the paragraph the previous disabled field goes back to the default state. Any suggestions /examples will be helpful. Below is my code. Thanks.

    function hook_form_alter(&$form, FormStateInterface $form_state, $form_id) {
      //Ajax callback on change event
      if (isset($form['field_link_type'])) {
        $form['field_select_sample']['widget']['#ajax'] = array(
        'callback' => '_my_ajaxcallback',
        'event' => 'change',
       );
      }
     }

    function _my_ajaxcallback(array $form, FormStateInterface $form_state) {


      $response = new \Drupal\Core\Ajax\AjaxResponse();

      //disable field_htext of paragraph field
      $response->addCommand(new \Drupal\Core\Ajax\InvokeCommand('.field--name-field-htext input', 'attr', array('disabled', 'disabled')));

      return $response;
    }

Updated code - In my callback -

    echo 'disabled - ' . $form_state->get('field_header_disabled');`
    $form_state->set('field_header_disabled', TRUE);`
    echo $form_state->get('field_header_disabled');
    return $response;

The output is something like - disabled - 1 on both first and second callbacks. On second callback I'm expecting the output to be something like disabled - 11

3
  • You'll have to make your changes more permanent. E.g. within your Ajax callback save a flag to $form_state, that the fields are disabled/enabled and in your hook_form_alter() read that flag from $form_state and set the field attributes accordingly. Commented Aug 24, 2018 at 11:31
  • Why do you expect a disabled - 11? - You echo the value only once... Commented Aug 27, 2018 at 13:15
  • The code is added in the callback function. So at first line it will output disabled - .I am ok with that coz this is the first callback and the field_header_disabled is not yet set. On the next line I'm setting the field_header_disabled and again echoed as 1 . Till here I concur with you. Now, when I trigger the callback function for the second time it should give me disabled - 1 in the first line and once again output 1 in the third line. So altogether it should output something as disabled - 11. Right?
    – wilNev
    Commented Aug 27, 2018 at 14:30

1 Answer 1

3

Your issue arises, as the paragraphs widget(s) itself do a lot of Ajax calls and you disable the field(s) in your browser only. So your paragraph form will be reloaded and re-rendered without knowing that the field has been disabled before.

To have the field(s) disabled on consecutive reloads, you need to make your changes more permanent.

You could e.g., save a flag to the $form_state using the FormStateInterface::set() method:

FormStateInterface
[...] it may be used to store information related to the processed data in the form, which will persist across page requests when the 'cache' or 'rebuild' flag is set.

This means, after you stored a custom flag in the $form_state and an ajax request to reload this form is made, it will be available within the $form_state of your hook_form_alter() implementation as well.

So all we have to do now, is checking for this flag in hook_form_alter() using the FormStateInterface::get() method and ensure the field will be disabled, if it has been set before.

A less abstract example:

/**
 * Callback for disabling field_htext.
 */
function _my_ajaxcallback(array $form, FormStateInterface $form_state) {
  $response = new \Drupal\Core\Ajax\AjaxResponse();

  // Disable field_htext of paragraph field.
  $response->addCommand(new \Drupal\Core\Ajax\InvokeCommand('.field--name-field-htext input', 'attr', array('disabled', 'disabled')));

  // Set a 'disabled' flag in form state.
  $form_state->set('field_htext_disabled', TRUE);

  return $response;
}

And in your form alter:

/**
 * Implements hook_form_alter().
 */
function hook_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Better use the form ID here and check, if you are at
  // your form in question, or even use a more specific hook as
  // hook_form_BASE_ID_alter() or hook_form_FORM_ID_alter().

  // Check our custom disabled flag.
  if (
    !empty($form_state->get('field_htext_disabled'))
    && isset($form['field_htext'])
  ) {
    // Set the 'disabled' attribute.
    $form['field_htext']['widget'][0]['value']['#attributes']['disabled'] = 'disabled';
  }

  // Add ajax callback on change event.
  if (isset($form['field_link_type'])) {
    $form['field_select_sample']['widget']['#ajax'] = array(
    'callback' => '_my_ajaxcallback',
    'event' => 'change',
   );
  }
 }
5
  • ++ for the example code.
    – wilNev
    Commented Aug 24, 2018 at 19:52
  • I tried setting the flag in callback. Unfortunately, the value showing as null on hook_form_alter().For debugging I tried to get the value inside the callback itself and tested by changing the select box multiple times. Still the value dont show. Posted the updated code on the question.
    – wilNev
    Commented Aug 26, 2018 at 17:04
  • @wilNev: The value will be NULL on your first form alter. Even on your first callback it will be NULL, as the flag is set after form alter has been invoked and the disabled property will be set within the frontend only. In the third round however (e.g. a callback of the paragraphs widget), it should be TRUE. Also note, that the form alter hook may be invoked multiple times during a post back. And that printing values before you send a response to the browser may have unintended side effects. Consider using a proper debugger instead or as lightweight alternative, temporarily print to error log. Commented Aug 27, 2018 at 13:10
  • Not sure if I missed out on anything. For now, I went with the approach suggested here .I will definitely have to check why the $form_state value is not accessible even after multiple callbacks.
    – wilNev
    Commented Aug 27, 2018 at 14:24
  • You could additionally try to explicitly set rebuild in your callback. This will ensure $form and $form_state being cached. Caching should happen automatically, since there is an #ajax property, but maybe it's not... - Try adding $form_state->setRebuild(TRUE); to your callback. Commented Aug 27, 2018 at 15:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.