0

I want to add fields depending on the first option selected. I also made a form with a similar behaviour but it wasn't a field widget.

I used this module as an example to make the form

I'm not sure if the way I implement this AJAX behavior should be different in a widget.

Can the behavior of this form be implemented in a field widget? I'm trying to look for examples of specifically field widgets implementing this but I still haven't found anything that could help `

 public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $value = isset($items[$delta]->value) ? $items[$delta]->value : '';
    $element = [];

    // Gather the number of names in the form already.
    $num_names = $form_state->get('num_names');
    // We have to ensure that there is at least one name field.
    if ($num_names === NULL) {
        $name_field = $form_state->set('num_names', 1);
        $num_names = 1;
    } 

    $element['breakpoints'] = [
      '#type' => 'select',
      '#title' => $this->t('Breakpoint group'),
      '#options' => $this->getBreakpointsGroups(),
      '#default_value' => $value,
      '#empty_option' => $this->t('-Select a breakpoint group-'),
    ];   



    $element['images_fieldset'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('Load images for each breakpoint'),
        '#prefix' => '<div id="breakpoint-wrapper">',
        '#suffix' => '</div>',
    ];

    for ($i = 0; $i < $num_names; $i++) {
        $element['images_fieldset']['image'][$i] = [
            '#type' => 'image',
            '#title' => $this->t('Image'),
            '#name' => "Name"
        ];
    }

    $element['images_fieldset']['submit'] = [
        '#type' => 'submit',
        '#title' => 'Submit',
        '#submit' => ['::submitForm'],
        '#value' => $this->t("submit"),
        '#ajax' => [
            'callback' => '::loadImageFields',
            'wrapper' => 'breakpoint-wrapper',
        ],
    ];


    return ['value' => $element];
}

/**
 * Returns a list of breakpoints.
 *
 * @return array
 *   An associative array of breakpoints, suitable to use as form
 *   options.
 */
protected function getBreakpointsGroups() {
    $breakpoints = \Drupal::service('breakpoint.manager')->getGroups();
    $breakpoint_names = array_keys($breakpoints);
    $breakpoint_group = array();
    foreach ($breakpoint_names as $name) {
        $breakpoint_group += [$name => $name];
    }
    return $breakpoint_group;
}

protected function submitForm($form, &$form_state) {
    $state = $form_state->getTriggeringElement();
    $breakpoint= $state['#value'];
    $array = array();

    $breakpoint = \Drupal::service('breakpoint.manager')->getBreakpointsByGroup($breakpoint);
    $breakpoints_name = array_keys($breakpoint);

    foreach ($breakpoints_name as $breakpoint_definition) {
        $mediaQuery = $breakpoint[$breakpoint_definition]->getMediaQuery();
        array_push($array,$mediaQuery);
    }      

    $name_field = $form_state->get('num_names');
    $form_state->set('num_names',count($array));

    $form_state->setRebuild();

}

public function loadImageFields(array $form, FormStateInterface $form_state) {
    return $form['images_fieldset'];
 }

}

6
  • I'm not sure without testing but I wonder if the way you are creating the wrapper element with its ID is correct. Most of the working examples I can find use '#prefix' and '#suffix' to add a wrapper div. Commented Apr 26, 2022 at 13:54
  • @AlfredArmstrong I edited the code to put what I got so far! The widget does what it needs to do (generate fields) but the values don't get saved! Commented Apr 26, 2022 at 14:40
  • I can't see anything in your element code that gets the current value and sets the form up accordingly. (Typically you need $items[$delta]->value). You'll want the form to match how it would be if someone had selected that value and it had updated by ajax. For the value to be stored, by default it needs to be under $element['value'] so you might want to change your field item keys to be $element['value']['breakpoints'] and so on. Commented Apr 26, 2022 at 15:24
  • Thanks. The selected value of the dropdown gets saved but I still do not know how to add the fields depending on the dropdown. I edited my changes if you happen to know how to do it. The fields can't be added via AJAX but I don't know how to add them in another way. I tried adding them inside the formElement function but it doesn't work the same way as a normal drupal form. Commented Apr 27, 2022 at 14:19
  • 1
    Thanks, I already got it figured out. I'll post the solution later. Commented Apr 29, 2022 at 10:05

1 Answer 1

0

The point is, you can't modify Drupal's internal form structure in an Ajax callback. So you'll need a submit handler, either for the field or for the complete widget, do the form modifications there and add a $form_state->setRebuild().

Ajax callbacks basically modify the HTML in the browser, that's all they do. They are called after the validation and submission has run.

2
  • Thanks for your answer! A submit handler? I'll try to do that. If you can point me out where to look it up I'd be grateful, but I'll search it anyways. Commented Apr 27, 2022 at 16:45
  • If you have time you can check my changes. Thanks anyways. Commented Apr 27, 2022 at 21:17

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.