web-dev-qa-db-fra.com

Comment changer la valeur par défaut d'un champ avec AJAX?

En relation avec ma question précédente: les champs de formulaire créés via Ajax n'ont pas d'attributs d'élément

J'ai un champ de date et une série de champs de texte et de nombre dont les valeurs par défaut doivent changer en fonction de la valeur du champ de date. J'ai mis à jour mon code pour qu'il fonctionne de cette façon:

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['date'] = array(
        '#type' => 'date',
        '#ajax' => [
            'callback' => '::dateCallback',
            'wrapper' => 'wrapper',
        ],
        '#default_value' => date("Y-m-d")
    );
    $form['wrapper'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'wrapper'],
    ];

    //insert logic to determine value of a variable called $field1    
    $form['wrapper']['options'] = array(
        '#type' => 'fieldset',
        '#attributes' => array('class' => array('options'))
    );
    $form['wrapper']['options']['field1'] = array(
        '#type' => 'textfield',
        '#title' => "Field 1",
        '#value' => $field1
    );
    $form['wrapper']['table'] = array(
        '#type' => 'table',
        '#title' => t('Table'),
        '#header' => array("H1", "H2", "H3"),
        '#attributes' => array('class' => array('custom-table'))
    );
    //insert logic to generate table rows
    return $form;
}

/**
 * Implements callback for Ajax event on date selection.
 *
 * @param array $form
 *   From render array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   Current state of form.
 *
 * @return array
 *   Date selection section of the form.
 */
public function dateCallback(array &$form, FormStateInterface $form_state) {
    return $form['wrapper'];
}

Il y a 2 problèmes que j'ai avec ceci:

1) L'implémenter de cette manière, de sorte que la propriété #value Soit modifiée lorsque le champ de date est modifié, fonctionne techniquement, cependant si l'utilisateur choisit ensuite de modifier l'une des valeurs de champ de texte, ce qui n'est pas reflété dans le $form_state Et est remplacé par le dernier paramètre #value Dans buildForm().

2) J'ai également essayé d'utiliser #default_value À la place, mais la valeur dans le champ ne sera pas mise à jour si elle contient déjà quelque chose (ce qu'elle fait habituellement dès la première fois que #default_value Est défini dans buildForm()). J'ai vu des discussions comme celle-ci suggérant de désactiver la valeur dans $form_state Avant de redéfinir #default_value, Cependant toutes ces suggestions sont pour Drupal 7 où $form_state Est une structure de données complètement différente.

Existe-t-il un moyen connu de faire ce que j'essaie d'accomplir?

Mise à jour: j'ai essayé à nouveau la méthode 2 en ajoutant $form_state->unsetValue('field1'); avant de déclarer $form['wrapper']['options']['field1'], Mais cela n'a pas changé le comportement.

5
saramm1

Paramètre de la méthode 1 #value ne permet en effet pas à l'utilisateur de saisir des données.

Ainsi, la méthode 2 définissant #default_value est, je pense, toujours la meilleure approche. Comme l'ancienne astuce de D7, la suppression de la valeur dans $ form_state, ne fonctionne plus, vous pouvez essayer celle-ci:

Créez le champ dans une sous-clé, qui est incrémentée pour chaque demande. Définissez la propriété #tree au premier niveau du champ, vous récupérez donc la valeur du champ sous forme de tableau [$key => $value]:

$form['wrapper']['options']['field1']['#tree'] = TRUE;

if ($form_state->hasValue('field1')) {
  $key = key($form_state->getValue('field1'));
  $value_field1 = current($form_state->getValue('field1')); 
  $key++;
}
else {
  $key = '0';
  $value_field1 = NULL;
}

// insert logic to determine new field value
// but check, if there is user input in $value_field1, that you don't want to overwrite

$form['wrapper']['options']['field1'][$key] = [
  '#type' => 'textfield',
  '#title' => 'Text 1',
  '#default_value' => $value_field1,
];
3
4k4

Une solution pour ajouter une valeur par défaut au champ après le rappel, mais avec une option permettant à l'utilisateur de modifier l'entrée:

ajoutez la valeur aux attributs de champ: '# attributes' => array ('value' => array ($ form_state-> getValue ('option2'))),

        $o = [];
    $form['option1'] = array(
        '#type' => 'select',
        '#size' => 1,
        '#options' => ['a' => 'A', 'b' => 'B'],
        '#title' => $this->t('option 1'),
        '#required' => TRUE,
        '#ajax' => array(
            'callback' => array($this, 'next'),
            'wrapper' => 'option2',
        ),
    );

    if ($form_state->getValue('option1') == 'a') {
        $o = [1 => 'one', 2 => 'two'];
    }
    if ($form_state->getValue('option1') == 'b') {
        $o = [3 => 'three', 4 => 'four'];
    }

    $form['option2'] = array(
        '#type' => 'select',
        '#size' => 1,
        '#options' => $o,
        '#title' => t('option 2'),
        '#required' => TRUE,
        '#prefix' => "<div id='option2'",
        '#suffix' => '</div>',
        '#ajax' => array(
            'callback' => array($this, 'get_data'),
            'wrapper' => 'data',
        ),
    );

    $form['data'] = [
        '#type' => 'textfield',
        '#id' => 'test',
        '#title' => t("choice") . " " . $form_state->getValue('option2'),
        '#default_value' => $form_state->getValue('option2'),
        '#size' => 5,
        '#attributes' => array('value' => array($form_state->getValue('option2'))),
        '#prefix' => "<div id='data'",
        '#suffix' => '</div>',
    ];

    $form['actions']['submit'] = array(
        '#type' => 'submit',
        '#value' => $this->t('Test'),
        '#suffix' => ''
    );

    return $form;
}

/**
 * callback functions
 */
public function next(array &$form, FormStateInterface $form_state) {
    return $form['option2'];
}

public function get_data(array &$form, FormStateInterface $form_state) {
    return $form['data'];
}

public function validateForm(array &$form, FormStateInterface $form_state) {

}

public function submitForm(array &$form, FormStateInterface $form_state) {
    dpm($form_state->getValue('data'));
}
0
arnaudom

Il existe une autre façon de faire la même chose: définissez la propriété #value sur le rappel ajax.

    <?php

    namespace Drupal\drupal_miseries\Form;

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

    class AjaxResponse extends FormBase {
      protected $ts_values = [
        'ts1' => [
          'values1' => [
            'id' => 1,
            'description' => 'Valor1',
            'status' => '1',
          ],
          'values2' => [
              'id' => 2,
              'description' => 'Valor2',
              'status' => 2,
          ],
        ],
      ];

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

      public function ajaxTableSelect(array &$form, FormStateInterface $form_state) {
        $element = $form_state->getTriggeringElement();
        if (isset($element) && $element['#type'] == 'checkbox') {
          $check_value = $element['#return_value'];
          $textfield_ts = $this->ts_values['ts1'][$check_value]['description'];
          $form['ts_textfield']['textfield']['#value'] = $textfield_ts;
        }

        return $form['ts_textfield'];
      }

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

        $form['ts_container'] = [
          '#type' => 'container',
          '#attributes' => ['id' => 'ts-container'],
        ];

        $header = [
          'id' => $this->t('ID'),
          'description' => $this->t('Description'),
          'status' => $this->t('Status'),
        ];

        $form['tableselect'] = [
          '#type' => 'tableselect',
          '#description' => $this->t('Test Tableselect'),
          '#header' => $header,
          '#options' => $this->ts_values['ts1'],
          '#empty' => $this->t('No values'),
          '#ajax' => [
            'callback' => [$this, 'ajaxTableSelect'],
            'wrapper' => 'ts-textfield',
          ],
        ];

        $form['ts_textfield'] = [
          '#type' => 'container',
          '#attributes' => ['id' => 'ts-textfield'],
        ];

        $form['ts_textfield']['textfield'] = [
          '#type' => 'textfield',
          '#description' => $this->t('Value fill by ajax'),
          '#title' => $this->t('Ajax Textfield'),
        ];

        $form['actions'] = [
          '#type' => 'actions',
        ];

        $form['action']['submit'] = [
          '#type' => 'submit',
          '#value' => $this->t('Submit'),
        ];

        return $form;
      }

      public function submitForm(array &$form, FormStateInterface $form_state) {
        dpm($form_state->getValue('tableselect'));
        dpm($form_state->getValue('textfield'));
      }
    }

Lorsque vous cliquez sur une case à cocher de sélection de tableau, le champ de texte est défini avec la valeur de la case à cocher => si vous cliquez sur "soumettre", la valeur de la case à cocher est affectée au champ de texte.

Lorsque vous cliquez sur une case à cocher de sélection de tableau, le champ de texte est défini avec la valeur de la case à cocher => si vous modifiez le champ de texte manuellement et cliquez sur "Soumettre", une nouvelle valeur sera affectée au champ de texte.

mais ....... Est-ce la bonne façon de procéder?

0
Javier Martín

J'ai résolu ce problème en utilisant le rappel AJAX pour recharger la page, plutôt que de renvoyer le formulaire. Par exemple:

$path = '/path/to/form';
$response = new AjaxResponse();
$response->addCommand(new RedirectCommand($path));
return $response;

C'est plus lent que de renvoyer le formulaire, mais c'est beaucoup moins de code, surtout si vous parlez d'un formulaire complexe avec beaucoup de valeurs par défaut.

0
Rob Squires