Рейтинг:1

Несколько форм на странице

флаг cn

Я пытаюсь заставить несколько форм работать на дисплее представлений. Все формы используют AJAX, но они мешают друг другу.

Одной из форм является форма массовых операций представлений, которая превращает таблицу представлений в форму «представления». Вторая форма — это форма «быстрого редактирования», доступная для каждой строки в представлении. Проблема в том, что когда я отправляю любую из форм из быстрого редактирования, он также пытается отправить форму «viewsForm» (чего делать не следует), что приводит к ошибкам проверки в этой форме. Он также не принимает мой обратный вызов ajax для моей пользовательской формы, о чем свидетельствует «обратный вызов ajax пуст или не может быть вызван» в dblog.

Если я отключу массовые операции просмотра, это будет работать так, как задумано, но с несколькими формами на странице я не могу понять, как сообщить кнопке «Отправить», которую я использую, только для отправки формы, принадлежащей кнопке отправки.

Я предоставил свой класс построителя формы для справки

<?php

пространство имен Drupal\request_system\Form;

используйте Drupal\Core\Form\FormBase;
используйте Drupal\Core\Form\FormStateInterface;
используйте Drupal\Core\Ajax\AjaxResponse;
используйте Drupal\Core\Ajax\ReplaceCommand;
используйте Drupal\Core\Ajax\HightlightCommand;

/**
 * Обеспечивает форму запроса системы.
 */
класс QuickEditForm расширяет FormBase {

  публичный $sub_id = 0;
  публичный $entity_id = 0;

  /**
   * {@inheritdoc}
   */
  публичная функция getFormId() {
    вернуть 'request_system_quick_edit-'. $это->sub_id;
  }

  /**
   * {@inheritdoc}
   */
  общедоступная функция buildForm (массив $ form, FormStateInterface $ form_state) {

    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($this->entity_id);
    
    $опции = [];

    $options['_none'] = '- Выберите один -';

    если ($entity->bundle() == 'book_request') {
      $statuses = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
        'vid' => 'book_request_status',
      ]);
    }

    // Показывать только "доступно у поставщика" и "ожидание"
    foreach ($статусы как $статус) {
      if ($status->getName() == 'В ожидании' || $status->getName() == 'Доступно от поставщика') {
        $options[$status->id()] = $status->getName();
      }
      
      если ($status->id() == $entity->field_request_status->getString()) {
        $options[$status->id()] = $status->getName();
      }
    }

    $form['quick_edit'] = [
      '#type' => 'контейнер',
      '#id' => 'быстрое редактирование-обертка-'. $это->sub_id,
    ];

    $form['quick_edit']['статус'] = [
      '#тип' => 'набор полей',
      '#title' => 'Обновления статуса',
      '#name' => 'обёртка-обновления',
    ];

    if (!$entity->field_aph_shipment_number->isEmpty() || !$entity->field_library_shipment_number->isEmpty()) {
      $form['quick_edit']['статус']['значение'] = [
        '#type' => 'предмет',
        '#title' => 'Статус запроса: ',
        '#markup' => \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($entity->field_request_status->getString())->getName(),
      ];

      // Показать сообщение о том, что товар является частью поставки
      $form['quick_edit']['status']['shipment_number'] = [
        '#markup' => 'Этот запрос является частью доставки.',
      ];
    }
    еще {
      // Отключите это поле, если статус запроса не «Ожидание» или «Доступно у поставщика», или если товар относится к отгрузке
      $form['quick_edit']['статус']['значение'] = [
        '#тип' => 'выбрать',
        '#title' => 'Статус',
        '#options' => $options,
        '#default_value' => $entity->field_request_status->getString(),
      ];

      if ($entity->field_request_status->getString() != \Drupal\request_system\Controller\RequestSystemController::getStatus('Pending') && $entity->field_request_status->getString() != \Drupal\request_system\Controller\ RequestSystemController::getStatus('Доступно у поставщика')) {
        $form['quick_edit']['status']['value']['#disabled'] = TRUE;
      }
    }

    $form['quick_edit']['статус']['сообщение'] = [
      '#тип' => 'текстовое поле',
      '#title' => $this->t('Сообщение'),
    ];

    $form['quick_edit']['status']['notify_user'] = [
      '#type' => 'флажок',
      '#title' => 'Уведомить заемщика',
    ];

    // Разрешить редактирование каталога APH #

    $form['quick_edit']['другое'] = [
      '#тип' => 'набор полей',
      '#title' => 'Другое',
      '#name' => 'другая-обертка',
    ];

    $form['quick_edit']['other']['aph_catalog_number'] = [
      '#тип' => 'текстовое поле',
      '#title' => 'Каталог APH №',
      '#default_value' => $entity->field_attached_copy_aph_number->getString(),
      '#description' => $entity->field_attached_copy_main_record->isEmpty() ? '' : 'Невозможно изменить каталожный номер APH при назначении основной записи.',
      '#disabled' => $entity->field_attached_copy_main_record->isEmpty() ? ЛОЖЬ ПРАВДА,
    ];

    $form['quick_edit']['id'] = [
      '#type' => 'скрытый',
      '#value' => $this->entity_id,
    ];

    $form['quick_edit']['actions'] = [
      '#type' => 'действия',
    ];
    $form['quick_edit']['actions']['submit'] = [
      '#type' => 'отправить',
      '#value' => $this->t('Сохранить'),
      '#ajax' => [
        'обратный вызов' => '::quickEditAjax',
        'обертка' => 'быстрое редактирование-обертка-'. $это->sub_id,
      ],
      '#validate' => '::validate',
      '#limit_validation_errors' => [['id'],['status']],
      '#submit' => ['::quickEditAjaxSubmit'],
    ];

    // $form['quick_edit']['actions']['cancel'] = [
    // '#type' => 'отправить',
    // '#value' => 'Отмена',
    // ];

    вернуть $ форму;
  }

  /**
   * {@inheritdoc}
   */
  общедоступная функция validateForm (массив и $ форма, FormStateInterface $ form_state) {
    $values ​​= $form_state->getValues();

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

    if ($values['status'] == \Drupal\request_system\Controller\RequestSystemController::getStatus("Отправлено из библиотеки займов")) {
      если (счетчик($entity->field_imcid->referencedEntities()) == 0) {
        $form_state->setErrorByName('status','Невозможно пометить этот элемент как отправленный, так как элемент библиотеки не прикреплен.');
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  публичная функция submitForm (массив и $ форма, FormStateInterface $ form_state) {

  }

  публичная функция quickEditAjax(&$form, FormStateInterface $form_state) {
    $values ​​= $form_state->getValues();

    если ($form_state->hasAnyErrors()) {
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#вес' => -1000,
      ];
      $form['#sorted'] = ЛОЖЬ;
    }
    
    $response = новый AjaxResponse();

    $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']));

    вернуть $ответ;
  }

  общедоступная функция quickEditAjaxSubmit(&$form, FormStateInterface $form_state) {
    $values ​​= $form_state->getValues();

    // Сначала загружаем сущность
    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($values['id']);

    $entity->set('field_request_status',$values['status']);
    $сущность->сохранить();

    $form_state->setRebuild();
  }

}

И способ, которым я отображаю форму, - через

$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);

Похоже, что когда представление отображается, оно объединяет все формы в один, поэтому, когда вы нажимаете «Сохранить» в подчиненной форме, оно фактически отправляет форму массовых операций представлений. Я не уверен, как это решить или заставить его прекратить это делать.

Я уже две недели ломаю голову над этим, пытаясь решить эту проблему, и не могу понять, в чем проблема.

Любая помощь будет ОЧЕНЬ оценена.

РЕДАКТИРОВАТЬ: я приложил скриншот того, чего мы пытаемся достичь. Флажок слева — это массовая операция просмотра, форма «быстрое редактирование» находится справа через «расширяемый столбец таблицы».

Демонстрация функциональности

флаг cn
Наличие `` является недопустимым HTML, то, что произойдет в этой ситуации, зависит от браузера. Думаю, я прав, говоря, что все современные браузеры просто игнорируют внутренний ``)
Ex0r avatar
флаг cn
VBO не оборачивает таблицу в форму, представления делают это, используя метод viewsForm, который он предоставляет, поэтому, скорее всего, потребуется изменить то, как работает представление, чтобы сделать что-то подобное.Я уже использую form_alter в форме, чтобы изменить некоторые вещи, которые делает VBO, но он делает это на уровне представления, а не на уровне отдельной строки, что мне и нужно.
флаг cn
Хорошо, план Б, вероятно, вылетел из окна, и его было бы сложно реализовать повторно. Однако уровень строки должен быть доступен, поскольку его использует VBO - я предполагаю, что есть обработчик поля, который использует API модуля для получения контекста формы, чтобы он мог отображать флажок для каждой строки. Возможно, ваш подход может быть таким же. Вам нужно будет заставить вашу функциональность работать в форме VBO и, возможно, изменить ее проверку/и т. д., но, учитывая характер реализации и то, что позволяет HTML, я не уверен, что альтернатива была бы
флаг cn
Под «формой VBO» я подразумеваю «форму, которую VBO убеждает Views создать с помощью `ViewsBulkOperationsBulkForm::viewsForm`». Я просто смотрю на код и понимаю, почему ты застрял
Ex0r avatar
флаг cn
Да, не похоже, что то, чего мы пытаемся достичь, возможно. VBO использует viewsForm для создания элемента формы типа #checkbox в расположении столбца, в котором он установлен в представлении, но это не идеально, поскольку это не то, что мы хотим делать, поскольку столбец для быстрого редактирования находится в совершенно другом столбце, и в идеале будет работать независимо от функциональности массовых операций представлений.
Ex0r avatar
флаг cn
Я обновил свой вопрос, включив в него скриншот того, чего мы пытаемся достичь.
флаг cn
У меня возникло бы искушение вообще отказаться от традиционного маршрута формы и использовать JS для отправки данных на маршрут в вашем пользовательском модуле, который выполняет сохранение. Если нет чего-то очевидного, что я упустил, это выглядит технически возможным, но, вероятно, не стоит усилий, чтобы сделать это обычным способом.
Ex0r avatar
флаг cn
Я не уверен, что вы имеете в виду. Раньше я не работал с отправкой форм через Drupal с использованием Javascript. Поскольку я в основном являюсь бэкэнд-разработчиком, у меня нет большого опыта работы с интерфейсом Drupal.
Рейтинг:0
флаг cn

Если я отключу массовые операции просмотра, это будет работать как задумано, но с несколько форм на странице, я не могу понять, как сказать кнопку «отправить», которую я использую только для отправки формы, принадлежащей кнопка отправки.

Не просматривая весь код, если у вас есть несколько форм Ajax на странице, это должно помочь использовать уникальные ключи формы отправки так же, как вы делаете это для оболочки:

$form['quick_edit']['actions']['submit' . $this->sub_id] = [
  ...
  '#ajax' => [
    'обратный вызов' => '::quickEditAjax',
    'обертка' => 'быстрое редактирование-обертка-'. $это->sub_id,
  ],

В другом случае вы не можете вкладывать формы, как обсуждалось в комментариях.

В общем, вам нужно разместить элементы формы внутри существующей формы, которые затем могут выполнять свои собственные функции, используя обратные вызовы submit и ajax и игнорируя остальную часть формы. Это можно сделать в простой форме alter hook или в более сложной системе. Для форм сущностей Drupal имеет подчиненные формы, реализованные в плагинах виджетов полей, для реализации плагинов полей массовых форм представлений. представленияФорма ($ форма, $ форма_состояние). Если вы используете один из них, следуйте тому, как они это делают.

Ex0r avatar
флаг cn
Я использую hook_form_alter прямо сейчас, чтобы изменить операции и рабочий процесс VBO. Я попытался использовать это, чтобы добавить в форму отдельные поля для каждой строки, но он не помещает их в правильное расположение столбца/поля, как должно, и не отображает все поля формы. В настоящее время я использую подключаемый модуль поля настраиваемых представлений для отображения форм в правильном столбце таблицы, но обработчики и кнопки отправки ajax при нажатии фактически запускают обработчик и проверку отправки vbo. У вас есть ссылка на документацию Drupals для подчиненных форм? Я не могу найти ничего, чтобы продемонстрировать, что это мы
4uk4 avatar
флаг cn
Подформы? Они автоматически создаются для полевых виджетов.Это был бы совершенно другой подход, не использующий массовую форму Views, а отображающий объекты в сетке, где вы можете прикрепить форму объекта для каждого объекта.
Ex0r avatar
флаг cn
Я использую VBO для различных функций. По сути, я пытаюсь создать две разные формы на странице. Один, чтобы вы могли выполнять быстрые действия над отдельными элементами строки, а другой, чтобы вы могли выбрать несколько строк и выполнять над ними различные «массовые действия». Похоже, я не могу делать то, что хочу, пока выполняются массовые операции просмотра, что воняет. Мне придется придумать другое решение.
Ex0r avatar
флаг cn
Форма, которую я отображаю прямо сейчас в каждой строке, представляет собой настраиваемое поле представлений, которое использует приведенный выше код рендеринга для рендеринга новой формы в каждой строке. Плагин поля — это «поддельное» поле, которое просто отображает вывод и форму в строку в соответствующем столбце поля в таблице. Кажется, нет способа создать виджет поля представлений, а если и есть, то я упустил его в документации.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.