Puncte:1

Forme multiple pe pagină

drapel cn

Încerc să fac mai multe forme să funcționeze într-un afișaj de vizualizări. Toate formularele folosesc AJAX, dar par să interfereze unele cu altele.

Un formular este formularul Views Bulk Operations care transformă tabelul de vizualizări într-un „viewsForm”. Al doilea formular este un formular de „editare rapidă” disponibil pe fiecare rând din vizualizare. Problema este că atunci când trimit oricare dintre formularele din editarea rapidă, încearcă să trimită și formularul „viewsForm” (ceea ce nu ar trebui să facă), rezultând erori de validare pe formularul respectiv. De asemenea, nu preia apelul meu ajax pentru formularul meu personalizat, așa cum arată „callbackul ajax este gol sau nu poate fi apelat” din dblog.

Dacă dezactivez operațiunile de vizualizare în bloc, acest lucru funcționează conform intenției, dar cu mai multe formulare pe pagină, nu îmi pot da seama cum să spun butonului „trimitere” pe care îl folosesc pentru a trimite doar formularul care aparține butonului de trimitere.

Am furnizat clasa mea de constructor de forme pentru referință

<?php

spațiu de nume Drupal\sistem_cerere\Form;

utilizați Drupal\Core\Form\FormBase;
utilizați Drupal\Core\Form\FormStateInterface;
utilizați Drupal\Core\Ajax\AjaxResponse;
utilizați Drupal\Core\Ajax\ReplaceCommand;
utilizați Drupal\Core\Ajax\HightlightCommand;

/**
 * Oferă un formular de cerere de sistem.
 */
clasa QuickEditForm extinde FormBase {

  public $sub_id = 0;
  public $entity_id = 0;

  /**
   * {@inheritdoc}
   */
  funcția publică getFormId() {
    returnează „request_system_quick_edit-” . $this->sub_id;
  }

  /**
   * {@inheritdoc}
   */
  funcția publică buildForm(array $form, FormStateInterface $form_state) {

    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($this->entity_id);
    
    $opțiuni = [];

    $options['_none'] = '- Selectați una -';

    dacă ($entity->bundle() == 'book_request') {
      $status = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
        'vid' => 'book_request_status',
      ]);
    }

    // Afișează numai „disponibil de la furnizor” și „În așteptare”
    foreach ($status ca $status) {
      if ($status->getName() == „În așteptare” || $status->getName() == „Disponibil de la furnizor”) {
        $options[$status->id()] = $status->getName();
      }
      
      if ($status->id() == $entity->field_request_status->getString()) {
        $options[$status->id()] = $status->getName();
      }
    }

    $form['quick_edit'] = [
      '#type' => 'container',
      '#id' => 'Quick-edit-wrapper-'. $this->sub_id,
    ];

    $form['quick_edit']['status'] = [
      '#type' => 'fieldset',
      '#title' => 'Actualizări de stare',
      '#name' => 'update-wrapper',
    ];

    dacă (!$entity->field_aph_shipment_number->isEmpty() || !$entity->field_library_shipment_number->isEmpty()) {
      $form['quick_edit']['status']['value'] = [
        '#type' => 'articol',
        '#title' => 'Starea solicitării: ',
        '#markup' => \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($entity->field_request_status->getString())->getName(),
      ];

      // Afișează mesajul care indică că articolul face parte dintr-o expediție
      $form['quick_edit']['status']['shipment_number'] = [
        '#markup' => 'Această solicitare face parte dintr-o expediere.',
      ];
    }
    else {
      // Dezactivează acest câmp dacă starea cererii nu este „În așteptare” sau „Disponibil de la furnizor” sau dacă articolul aparține unei expedieri
      $form['quick_edit']['status']['value'] = [
        '#type' => 'selectați',
        '#title' => 'Stare',
        '#options' => $opțiuni,
        '#default_value' => $entity->field_request_status->getString(),
      ];

      if ($entity->field_request_status->getString() != \Drupal\request_system\Controller\RequestSystemController::getStatus('În așteptare') && $entity->field_request_status->getString() != \Drupal\request_system\Controller\ RequestSystemController::getStatus('Disponibil de la furnizor')) {
        $form['quick_edit']['status']['value']['#disabled'] = TRUE;
      }
    }

    $form['quick_edit']['status']['mesaj'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Mesaj'),
    ];

    $form['quick_edit']['status']['notify_user'] = [
      '#type' => 'caseta de selectare',
      '#title' => 'Anunțați împrumutatul',
    ];

    // Permite editarea catalogului APH #

    $form['quick_edit']['other'] = [
      '#type' => 'fieldset',
      '#title' => 'Altele',
      '#name' => 'alt-wrapper',
    ];

    $form['quick_edit']['other']['aph_catalog_number'] = [
      '#type' => 'câmp text',
      '#title' => 'Număr de catalog APH',
      '#default_value' => $entity->field_attached_copy_aph_number->getString(),
      '#description' => $entity->field_attached_copy_main_record->isEmpty() ? '' : 'Nu se poate schimba numărul de catalog APH atunci când este atribuită o înregistrare principală.',
      '#disabled' => $entity->field_attached_copy_main_record->isEmpty() ? FALS ADEVARAT,
    ];

    $form['quick_edit']['id'] = [
      '#type' => 'ascuns',
      '#value' => $this->entity_id,
    ];

    $form['quick_edit']['actions'] = [
      '#type' => 'acțiuni',
    ];
    $form['quick_edit']['actions']['submit'] = [
      '#type' => 'trimite',
      '#value' => $this->t('Salvare'),
      '#ajax' => [
        'callback' => '::quickEditAjax',
        'wrapper' => 'quick-edit-wrapper-'. $this->sub_id,
      ],
      '#validate' => '::validate',
      '#limit_validation_errors' => [['id'],['status']],
      '#submit' => ['::quickEditAjaxSubmit'],
    ];

    // $form['quick_edit']['actions']['cancel'] = [
    // '#type' => 'trimite',
    // '#value' => 'Anulează',
    // ];

    returnează $form;
  }

  /**
   * {@inheritdoc}
   */
  funcția publică validateForm(matrice &$form, FormStateInterface $form_state) {
    $valori = $form_state->getValues();

    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($values['id']);

    if ($values['status'] == \Drupal\request_system\Controller\RequestSystemController::getStatus(„Livrat din biblioteca de împrumut”)) {
      if (count($entity->field_imcid->referencedEntities()) == 0) {
        $form_state->setErrorByName('status','Nu se poate marca acest articol livrat deoarece nu este atașat niciun articol din bibliotecă.');
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  funcția publică submitForm(matrice &$form, FormStateInterface $form_state) {

  }

  funcția publică quickEditAjax(&$form, FormStateInterface $form_state) {
    $valori = $form_state->getValues();

    dacă ($form_state->hasAnyErrors()) {
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -1000,
      ];
      $form['#sorted'] = FALS;
    }
    
    $răspuns = AjaxResponse nou();

    $status = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($values['status']);
    $response->addCommand(new ReplaceCommand('.request-status-'. $values['id'], $status->getName()));
    $response->addCommand(new ReplaceCommand('#quick-edit-wrapper-'. $this->sub_id,$form));
    $response->addCommand(new HightlightCommand('#row-'. $values['id']));

    returnează $răspuns;
  }

  funcția publică quickEditAjaxSubmit(&$form, FormStateInterface $form_state) {
    $valori = $form_state->getValues();

    // Încărcați mai întâi entitatea
    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($values['id']);

    $entity->set('field_request_status',$values['status']);
    $entity->salvare();

    $form_state->setRebuild();
  }

}

Și modul în care redau formularul este via

$form = \Drupal::classResolver()->getInstanceFromDefinition('Drupal\request_system\Form\QuickEditForm');
$form->sub_id = $entity->id();
$form->entity_id = $entity->id();
$build['form'] = \Drupal::formBuilder()->getForm($form);

Se pare că atunci când vizualizarea este redată, combină toate formularele într-un singur , așa că atunci când dați clic pe „Salvați” pe subformular, de fapt trimite formularul de operațiuni în bloc de vizualizări. Nu sunt sigur cum să rezolv acest lucru sau să o fac să nu mai facă asta.

Mă bat cu capul în asta timp de două săptămâni încercând să rezolv asta și nu pot să-mi dau seama care este problema.

Orice ajutor ar fi foarte apreciat.

EDIT: Am atașat o captură de ecran a ceea ce încercăm să realizăm. Caseta de selectare din stânga este vizualizarea operațiunii în bloc, formularul „editare rapidă” este în extrema dreaptă prin „coloana tabel extensibil”

Prezentare de funcționalitate

drapel cn
Având un `` este HTML nevalid, depinde de browser ce se întâmplă în acea situație. Cred că am dreptate când spun că toate browserele moderne vor ignora pur și simplu `-ul interior`)
Ex0r avatar
drapel cn
VBO nu împachetează tabelul într-un formular, vederile îl fac folosind metoda viewsForm pe care o expune, așa că cel mai probabil ar necesita modificarea modului în care funcționează Views pentru a face așa ceva.Folosesc deja form_alter pe formular pentru a schimba unele dintre lucrurile pe care le face VBO, dar o face la nivel de vizualizare, nu la nivel de rând individual, ceea ce trebuie să fac.
drapel cn
Ok, planul B este probabil ieșit din fereastră atunci, ar fi greu de reimplementat. Totuși, nivelul rândului trebuie să fie disponibil, deoarece VBO îl folosește - presupun că există un handler de câmp care utilizează API-ul modulului pentru a obține un context de formular, astfel încât să poată reda caseta de selectare pe rând. Poate că abordarea ta ar putea fi aceeași. Ar trebui să vă faceți funcționalitatea să funcționeze în cadrul formularului VBO și, eventual, să îi modificați validarea/etc, dar având în vedere natura implementării și ceea ce permite HTML, nu sunt sigur care ar fi alternativa
drapel cn
Prin „formular VBO” mă refer la „formularul pe care VBO îl convinge pe Views să îl creeze prin `ViewsBulkOperationsBulkForm::viewsForm`”. Mă uit doar la cod și văd de ce ești blocat
Ex0r avatar
drapel cn
Da, nu se pare că ceea ce încercăm să realizăm este posibil. VBO folosește viewsForm pentru a crea un element de formular de tipul #checkbox în locația coloanei în care este setată în vizualizare, dar asta nu este ideal, deoarece nu este ceea ce vrem să facem, deoarece coloana pentru quickedit este într-o coloană complet diferită, și, în mod ideal, ar funcționa independent de funcționalitatea operațiunilor în bloc de vizualizări.
Ex0r avatar
drapel cn
Mi-am actualizat întrebarea pentru a include o captură de ecran a ceea ce încercăm să realizăm.
drapel cn
Aș fi tentat să abandonez cu totul ruta tradițională de formular și să folosesc JS pentru a trimite datele către o rută din modulul personalizat care efectuează salvarea. Dacă nu există ceva evident care îmi lipsește, pare a fi posibil din punct de vedere tehnic, dar probabil că nu merită efortul de a o face în mod normal
Ex0r avatar
drapel cn
Nu sunt sigur ce vrei să spui prin asta. Nu am mai lucrat cu trimiterea de formulare prin Drupal folosind Javascript. Deoarece sunt în principal un dezvoltator backend, nu am prea multă experiență cu evenimentele din front end ale Drupal.
Puncte:0
drapel cn

Dacă dezactivez vizualizările operațiunilor în bloc, aceasta funcționează conform intenției, dar cu mai multe forme de pe pagină, nu îmi pot da seama cum să spun Butonul „trimite” pe care îl folosesc pentru a trimite doar formularul care aparține companiei buton de trimitere.

Fără a revizui întregul cod, dacă aveți mai multe formulare Ajax pe o pagină, ar trebui să vă ajute să utilizați chei unice de trimitere a formularului în același mod în care faceți acest lucru pentru wrapper:

$form['quick_edit']['actions']['submit' . $this->sub_id] = [
  ...
  '#ajax' => [
    'callback' => '::quickEditAjax',
    'wrapper' => 'quick-edit-wrapper-'. $this->sub_id,
  ],

În celălalt caz, nu puteți cuibărește forme așa cum sa discutat în comentarii.

În general, trebuie să plasați elementele formularului în formularul existent, care apoi își pot face propriile lucruri utilizând apeluri submit și ajax și ignorând restul formularului. Acest lucru se poate face într-o formă simplă de modificare a cârligului sau într-un sistem mai complicat. Pentru formularele de entitate, Drupal are subformulare implementate în pluginuri widget de câmp, pentru implementarea pluginurilor de câmp pentru formulare în bloc Views viewForm($form, $form_state). Dacă utilizați unul dintre acestea, atunci urmați modul în care o fac.

Ex0r avatar
drapel cn
Folosesc hook_form_alter chiar acum pentru a modifica operațiunile și fluxul de lucru VBO. Am încercat să-l folosesc pentru a adăuga câmpuri individuale pe rând în formular, dar nu le plasează în locația corectă a coloanei/câmpului în care ar trebui și nici nu redă toate câmpurile formularului. În prezent, folosesc un plugin de câmp de vizualizări personalizate pentru a reda formularele în coloana corectă a tabelului, dar manevrele și butoanele de trimitere ajax atunci când se fac clic declanșează de fapt gestionarea și validarea vbo submit. Aveți un link către documentația Drupals pentru subformulare? Nu găsesc nimic care să demonstreze că suntem noi
4uk4 avatar
drapel cn
Subformulare? Sunt construite automat pentru widget-uri de câmp.Ceea ce ar fi o abordare complet diferită, nefolosind un formular în bloc Views, ci afișând entități într-o grilă în care ați putea atașa un formular de entitate pentru fiecare entitate.
Ex0r avatar
drapel cn
Folosesc VBO pentru diferite funcționalități. În esență, încerc să construiesc două forme diferite pe pagină. Unul pentru a putea efectua acțiuni rapide pe elemente de rând individuale în linie și unul pentru a putea selecta mai multe rânduri și a efectua diferite „acțiuni în bloc” asupra acestora. Nu se pare că pot face ceea ce vreau să fac atâta timp cât operațiunile de vizualizare în vrac sunt în loc, ceea ce pute. Va trebui să vin cu o altă soluție.
Ex0r avatar
drapel cn
Formularul pe care îl redau acum pe fiecare rând este un câmp de vizualizare personalizat care utilizează codul de randare de mai sus pentru a reda un formular nou pe fiecare rând. Pluginul de câmp este un câmp „fals” care redă doar ieșirea și un formular pentru rândul din coloana de câmp corespunzătoare din tabel. Nu pare să existe o modalitate de a crea un widget de câmp de vizualizări sau, dacă există, îl lipsesc din documentație.

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.