Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue for a "two dimentionnal 'add another item' " with FormStateInterface::getTriggeringElement()

I'm learning drupal 8. I want create a page who contain a 'two dimensionnal' 'add another item' form. My code works well almost, but I have a strange behavior when I add rooms to a house (there is a strange value in my debug logs from the FormStateInterface::getTriggeringElement(), see to the bottom for the code and log)

First : I have two structures, houses and rooms. The user can create some houses and for each house, he can create some rooms :

enter image description here

When I add some houses, the form works fine :

enter image description here

When I add some rooms to the last house, the form works fine too :

enter image description here

But when I add some rooms to any "no-last" house, the form doesn't work fine (in the screenshot, I click one time to the "add room" in the block house '1', the label of the "house 1" became "house 2" (?!) and on click add 5 rooms (?!) :

enter image description here

Here my code and a strange debug log, I don't explain why I get this value (from the getTriggeringElement() in the room_addMoreSubmit callback and this is the problem I think)

<?php

namespace Drupal\projet\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class HouseForm extends FormBase {

  public function getFormId(){
    return 'custom_rooms_form';
  }

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



    $house_count = $form_state->get('house_count');

    if (is_null($house_count)) {
      $house_count = 1;
      $form_state->set('house_count', $house_count);
    }

    $form['house'] = array(
        //'#tree' => TRUE,
        '#prefix' => '<div id="house-replace">',
        '#suffix' => '</div>'
    );

    for ($house_delta = 0; $house_delta < $house_count; $house_delta++) {
      if (!isset($form['house'][$house_delta])) {

        $room_count[$house_delta] = $form_state->get('room_count_'.$house_delta);

        if (is_null($room_count[$house_delta])) {
          $room_count[$house_delta] = 1;
          $form_state->set('room_count_'.$house_delta, $room_count[$house_delta]);
        }

        dd($room_count, "room_COUNT");

        $form['house'][$house_delta]['room'] = array(
            '#type' => 'fieldset',
            '#title' => t('house : '.$house_delta),
            //'#tree' => TRUE,
            '#prefix' => '<div id="room-replace-'.$house_delta.'">',
            '#suffix' => '</div>'
        );

        for ($room_delta = 0; $room_delta < $room_count[$house_delta]; $room_delta++) {
          if (!isset($form['house'][$house_delta]['room'][$room_delta])) {
            $room = array(
                '#type' => 'textfield'
            );
            $check = array(
                '#type' => 'checkbox'
            );
            $form['house'][$house_delta]['room'][$room_delta] = array(
                '#type' => 'fieldset',
                '#title' => t('room : '.$house_delta.'.'.$room_delta),
            );
            $form['house'][$house_delta]['room'][$room_delta]['text'] = $room;
            $form['house'][$house_delta]['room'][$room_delta]['check'] = $check;
          }
        }

        $form['house'][$house_delta]['room']['add'] = array(
            '#type' => 'submit',
            '#name' => 'add',
            '#value' => t('Add room'),
            '#attributes' => array('class' => array('field-add-more-submit'), 'house_delta' => array($house_delta)),
            '#submit' => array(array(get_class($this), 'room_addMoreSubmit')),
            '#ajax' => array(
                'callback' => array($this, 'room_addMoreCallback'),
                'wrapper' => 'room-replace-'.$house_delta,
                'effect' => 'fade',
            ),
        );

      }
    }

    $form['house']['add'] = array(
        '#type' => 'submit',
        '#name' => 'add',
        '#value' => t('Add house'),
        '#attributes' => array('class' => array('field-add-more-submit')),
        '#submit' => array(array(get_class($this), 'house_addMoreSubmit')),
        '#ajax' => array(
            'callback' => array($this, 'house_addMoreCallback'),
            'wrapper' => 'house-replace',
            'effect' => 'fade',
        ),
    );


    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Create'),
    );

    return $form;
  }

  public function room_addMoreSubmit(array $form, FormStateInterface $form_state) {
    dd($form_state->getTriggeringElement(), "room : getTriggeringElement()"); // below, the log when I add a room to the house '1' (result see above  with the last screenshot: "the house 1" became "house 2" and one click add 5 rooms)
    $house = $form_state->getTriggeringElement()["#array_parents"][1];
    $c = $form_state->get('room_count_'.$house) + 1;
    $form_state->set('room_count_'.$house, $c);
    $form_state->setRebuild(TRUE);
  }

  public function room_addMoreCallback(array $form, FormStateInterface $form_state) {
    $house = $form_state->getTriggeringElement()["#array_parents"][1];
    return $form['house'][$house]['room'];
  }

  public function house_addMoreSubmit(array $form, FormStateInterface $form_state) {
    dd($form_state->getTriggeringElement()["#array_parents"], "house : getTriggeringElement()"); 
    $c = $form_state->get('house_count') + 1;
    $form_state->set('house_count', $c);
    $form_state->setRebuild(TRUE);
  }

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

}

The log ('dd' in the room_addMoreSubmit) when I click on the "add room" button in the house "1":

enter image description here

When I click on the "add room" button in the house number 1, getTriggeringElement return the array parents of the add button. And, as you can see, the parent is "2" not "1" (the house 1) So when I click on the "add room" button of the house 1, this is the house "2" which is identified and not the house "1".

I don't understand why...Use the getTriggeringElement is not the good way ?

like image 759
spacecodeur Avatar asked Oct 18 '22 23:10

spacecodeur


1 Answers

The solution :

$form['house'][$house_delta]['room']['add'] = array(
            '#type' => 'submit',
            '#name' => 'add-'.$house_delta,
            '#value' => t('Add room'),
            '#attributes' => array('class' => array('field-add-more-submit'), 'house_delta' => array($house_delta)),
            '#submit' => array(array(get_class($this), 'room_addMoreSubmit')),
            '#ajax' => array(
                'callback' => array($this, 'room_addMoreCallback'),
                'wrapper' => 'room-replace-'.$house_delta,
                'effect' => 'fade',
            ),
        );

The unique name was the issue of my problem. So, I change the name attribute.

like image 76
spacecodeur Avatar answered Oct 22 '22 23:10

spacecodeur