Puncte:3

Formularul AJAX folosind o subclasă de ContentEntityForm declanșează/invocă/apelează WidgetBase::massageFormValues() de două ori

drapel cn

Folosesc un formular AJAX. Acest formular îl construiesc dintr-o subclasă de ContentEntityForm. Entitatea editată de acest formular are un câmp MyField. Pentru a aduce toate valorile câmpului într-o structură adecvată pe care o folosesc massageFormValues() în MyFieldWidget clasa (subclasa de WidgetBase).

Mica problemă este: metoda massageFormValues() este apelat de două ori la fiecare trimitere. Nu există alte probleme cu formularul. Pot edita corect valorile din acest formular.

Deci este doar întrebarea de înțelegere: de ce Drupal sună massageFormValues() de două ori la fiecare trimitere.

Codul menționat și codul meu (foarte simplificat):

Controlerul meu ajax

clasa AjaxController extinde ControllerBase {
  ...
  ...

  funcția publică myController($eid) {

    $myEntity = $this->entityTypeManager()->getStorage('my_entity')->load($eid);
    $form = $this->entityFormBuilder()->getForm($myEntity, 'my_mode');
    $renderer = \Drupal::service('renderer');
    $ieșire = $renderer->renderRoot($form);
  
    $răspuns = AjaxResponse nou();
    $răspuns->addCommand(new OpenModalDialogCommand($titlu, $ieșire));
 
    returnează $răspuns;
  }
  ...
  ...
}

MyForm este o subclasă a ContentEntityForm și este a forma modului pentru modul modul_meu a Entității entitatea_mea:

clasa MyForm extinde ContentEntityForm {

 ...
 ...
  acțiuni ale funcției protejate (matrice $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);

    $actions['trimite'] = [
      '#type' => 'trimite',
      '#value' => t('Salvare'),
      '#ajax' => [
        'callback' => '::ajaxCallback',
        'event' => 'mousedown',
      ],
    ];

  returnează $acțiuni;
  }
  ...
  ...
}

Clasa mea de widgeturi de câmp:

clasa MyFieldWidget extinde WidgetBase implementează ContainerFactoryPluginInterface {
...
...

  funcția publică massageFormValues(matrice $valori, matrice $form, FormStateInterface $form_state) { 

    // ACEST COD ESTE NUMAT DE DOUA ORI LA FIECARE TRIMITERE A BUTONULUI MEU DE TRIMITE DEFINIT MAI SUS
    // DAR DE CE DE DOUA ORI?

    returnează $rightStructureValues;
  }

...
...
}
Puncte:4
drapel cn

Într-o solicitare Ajax, formularul este reconstruit de la zero. Acest lucru a fost adesea întrebat aici de ce metoda de construire a formularului este numită de două sau chiar de trei ori. Se pare că entitatea este reconstruită și atunci când formularul este trimis prin Ajax:

Drupal\Core\Entity\EntityForm::afterBuild

  /**
   * Elementul de formular #after_build callback: Actualizează entitatea cu datele trimise.
   *
   * Actualizează obiectul intern $this->entity cu valorile trimise atunci când
   * formularul este reconstruit (de exemplu, trimis prin AJAX), astfel încât ulterior
   * procesarea (de exemplu, apelurile inverse AJAX) se poate baza pe ea.
   */
  funcția publică afterBuild(array $element, FormStateInterface $form_state) {
    // Reconstruiți entitatea dacă #after_build este apelat ca parte a unui formular
    // reconstruiește, adică dacă procesăm intrarea.
    dacă ($form_state->isProcessingInput()) {
      $this->entity = $this->buildEntity($element, $form_state);
    }

    returnează $element;
  }

Aceasta va declanșa metoda menționată în widget-urile de câmp.

Hermann Schwarz avatar
drapel cn
Din păcate, nu am putut împiedica apelarea massageFormValues() de două ori în numele afterBuild(). Dar dacă poți descrie în detaliu cum funcționează, ar fi bine. Voi oferi propria mea soluție ca răspuns.
4uk4 avatar
drapel cn
Nu este nimic greșit în faptul că această metodă și întreaga construcție a formularului este apelată de două ori. Principalii menținători au decis să reconstruiască mai degrabă formularul (și entitatea în acest caz) decât să umple baza de date cu formulare Ajax stocate în cache, care nu sunt trimise niciodată.
Hermann Schwarz avatar
drapel cn
Înțeleg. Mulțumesc, 4k4. Recunosc, e micro optimizare pe care o fac :-).
Puncte:1
drapel cn

Soluția/soluția mea. massageFormValues() este încă apelat de două ori de către Drupal, dar logica mea va fi executată o singură dată, după ce validarea formularului este completă:

MyFieldWidgetClass.php:

clasa MyFieldWidget extinde WidgetBase implementează ContainerFactoryPluginInterface {
...
...

  funcția publică massageFormValues(matrice $valori, matrice $form, FormStateInterface $form_state) { 

    // massageFormValues() este apelat de două ori: pe validateForm și pe submitForm
    // avem nevoie doar de massageFormValues ​​o dată, după ce $form_state->isValidationComplete() este TRUE
    if(!$form_state->isValidationComplete()) {
      întoarcere [];
    }
    ...
    ...
    returnează $rightStructureValues;
  }

...
...
}

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.