2

I've created a AJAX block form that allows a user to specify the number of fields they would like to have available. like so

    $form['columnNum'] = [
        '#title'   => t('Number of Columns'),
        '#type'    => 'select',
        '#options' => [
            1         => '1',
            2         => '2',
            3         => '3',
        ],
        '#default_value' => $this->configuration['columnNum'],
        '#empty_option'  => t('-select-'),
        '#ajax'          => [
            'callback'      => [$this, 'columnCallback'],
        ],
    ];

    $columns = $this->colFieldGen($this->configuration['columnNum'], $this->configuration['columns']);

    $form['column_wrapper'] = [
        '#type'       => 'container',
        '#attributes' => ['id' => 'column_wrapper'],
        $columns,

    ];
return $form;

the colFieldGen form, generates the number of fields like so.

public function colFieldGen($num, array $config) {
    for ($i = 0; $i < $num; $i += 1) {
        $numTitle    = $i+1;
        $columns[$i] = [
            $i             => [
                '#type'       => 'details',
                '#title'      => t('Column '.$numTitle),
                '#open'       => FALSE,
                'columnTitle' => [
                    '#type'      => 'textfield',
                    '#title'     => t('Column Title'),
                ],
            ],
          ];

And below is the callback.

public function columnCallback(array&$form, FormStateInterface $form_state) {
        $response = new AjaxResponse();
        $columns = $this->colFieldGen($number, $this->configuration['columns']);

        $content = [
            '#type'       => 'container',
            '#attributes' => ['id' => 'column_wrapper'],
            $columns,
        ];

        $response->addCommand(new ReplaceCommand('#column_wrapper', $content));
        return $response;
    }

I'm using the replace command to replace the fields that were present in the container, with a set of new fields. However any of the data in the new fields aren't sent through form_state. Fields that existed already like $form['columnNum'] are sent through $form_state just fine.

Is there a way to see values of ajax created form elements in $form_state? Or is there a better way to do this entirely?

NOTE: This is all being performed in a blockForm if that makes any difference.


UPDATE:

I changed the field generator to be based on a form_state variable like so

if (empty($form_state->getValue('number'))) {
    $form_state->setValue('number', 1);
}

$columns = $this->colFieldGen($form_state->getValue('number'), $this->configuration['columns']);

and then in the AJAX call performed this

public function columnCallback(array&$form, FormStateInterface $form_state) {
    $form_state->setValue('number', 10);
    $form_state->setRebuild(true);
    return $form;
}

But the form never rebuilds with the new amount of specified fields. I receive the progress animation on change, so I know something is firing. I just get no results. To see if the form was attempting a rebuild I added

if (empty($form_state->getValue('number'))) {
    $form_state->setValue('number', 1);
} else {
    die($form_state->getValue('number'));
}

to have the form fail if the form_state already exists but it never dies.

3

Move all form building activities from the callback to the form build function.

The form elements you add in the callback go directly through javascript to the DOM in your browser. You see them as normal form elements, but the form API doesn't know that they are in your browser and will ignore them.

Edit for the questions in comments:

In the form build function you know that you are rebuilding because $form_state is filled with data. On the first run it is empty.

You have the number of columns in the value of the select element.

You should wait with handling of the configuration data until submit.

In general an ajax form should have the same code in form build as a normal form, because if jquery is not available, ajax will fallback to a normal rebuild.

  • How would I get the ajax call to fire the formbuild function again? – Matt Aug 11 '16 at 21:00
  • That happens automatically before the callback gets control. – 4k4 Aug 11 '16 at 21:05
  • I've tried that route but when I change the callback to just increase $this->configuration['columnNum'] and $form->setRebuild(true) and then return $form nothing happens. – Matt Aug 11 '16 at 21:55
  • I don't think that this belongs in the callback either. – 4k4 Aug 11 '16 at 22:08
  • 2
    By storing e.g. the element count in $form_state. You increase it there, then rebuild, then based on that build it. ajax must not contain any logic, just return what has been built already. – Berdir Aug 11 '16 at 22:26

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.