1

I'm having a form with a select list and a textbox. On-change of select list will trigger an ajax callback. The callback function will replace the default value of textbox with an updated value. But when I try to get the textbox value in buildForm() or if I try to submit the form, instead of the updated value the default value (old value which is set) is passed on submit handler. Below is the code -

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormStateInterface;


class MyAjaxForm extends ConfigFormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['output'] = [
        '#type' => 'textfield',
        '#size' => '60',
        '#value' => 'oldvalue',
        '#default_value' => 'oldvalue',
        '#attributes' => [
            'id' => ['edit-output'],
        ],
    ];


    $form['input'] = array(
        '#title' => t('Crust Size'),
        '#type' => 'select',
        '#description' => 'Select the desired pizza crust size.',
        '#options' => [
          'medium' => 'Medium',
          'large' => 'large',
         ],
        '#ajax' => [
            'callback' => [$this, 'seyHello'],
            'event' => 'change',
            'wrapper' => 'edit-output',
            'progress' => [
                'type' => 'throbber',
                'message' => t('Verifying entry...'),
            ],
        ],
    );

    return parent::buildForm($form, $form_state);
    dpm($form['output']['#value']);
    //even after the ajax callback return and the textbox is filled with 'newvalue', dpm returns 'oldvalue' still.
  }



  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    parent::submitForm($form, $form_state);

    dpm($form['output']['#value']);
    dpm($form_state->getValue('output'));
    //both returns 'oldvalue'


  }


  public function seyHello(array &$form, FormStateInterface &$form_state) : AjaxResponse {
    $elem = [
        '#type' => 'textfield',
        '#size' => '60',
        '#default_value' => 'newvalue',
        '#value' => 'newvalue',
        '#attributes' => [
            'id' => ['edit-output'],
        ],
    ];
    $renderer = \Drupal::service('renderer');
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand('#edit-output', 
    $renderer->render($elem)));
    $form_state->setRebuild(TRUE);
    return $response;
  }


}

I'm not sure why this is happening, it clearly seems to be the case of form values not getting updated after the ajax callback for me. Been debugging this for entire day. Any help/ suggestions would be lovely. Thanks.

  • An AJAX callback is just for setting form state and returning either an element to render or a command to execute. You can’t add new form elements (or change existing ones) in there, that needs to be done in the buildForm method. And don’t render things manually! – Clive Aug 28 '18 at 16:46
  • You need to apply the same fix as for the module Examples in this issue drupal.org/project/examples/issues/2774601 – 4k4 Aug 28 '18 at 17:13
  • @4k4 I'm not sure what exactly I need to change here. It would be great if you can provide an example code in a very abstract way.Thanks. – wilNev Aug 28 '18 at 17:46
1

The ajax callback returns the part of $form which is inside of the ajax wrapper:

  /**
   * Ajax callback for the color dropdown.
   */
  public function updateColor(array $form, FormStateInterface $form_state) {
    return $form['color_wrapper'];
  }

The wrapper has to be a div container.

Complete code example https://cgit.drupalcode.org/examples/tree/form_api_example/src/Form/AjaxColorForm.php

  • +1 for the example code. Will this be working for hook_form_alter() also as I'm trying to alter an existing backend form. – wilNev Aug 28 '18 at 18:19
  • Yes, the form alter hook is part of the form building and you can add form elements to return them in an ajax callback. – 4k4 Aug 28 '18 at 18:51
  • Yeah, I concur it works now. One final question, can't I use AjaxResponse() in the callback and return that instead of returning $form ? If yes, can you give a brief example of that too. Thanks. – wilNev Aug 28 '18 at 20:17
  • This is not necessary in this example, if you return a form array an ajax response is built automatically. – 4k4 Aug 28 '18 at 20:25

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.