Drupal 9 - Ajax 回调只工作一次

Drupal 9 - Ajax callback working only once

提问人:Juju 提问时间:8/22/2022 最后编辑:Juju 更新时间:8/27/2022 访问量:1247

问:

我正在 Drupal 9.4 上构建站点,我在用户表单 alter 的 .module 文件中的 Ajax 回调遇到了一些问题。

功能不是很复杂,我在一个字段中显示之前上传的图像(在多个图像字段中),并附带一个删除按钮。

另一个字段显示仍然可以上传的图像数量。 在每个删除按钮上调用回调以执行 2 项操作:

1-删除照片字段中对图像的引用。

2- 将可上传的图像数量增加 1。

在我的回调中,如果我只做 1,一切正常。但是,如果我将 ajax 响应与字段更新一起添加以增加数字,则第一次删除有效并且字段增加 1。

但是,如果我尝试删除第二个回调,则会出现一个错误,指出找不到回调。 Symfony\Component\HttpKernel\Exception\HttpException:指定的 #ajax 回调为空或不可调用。

这是我的代码:

function main_form_alter(&$form, $form_state, $form_id) {

  if ($form_id === 'user_form') {
    /** @var \Drupal\user\Entity\User $user */
    $user = $form_state->getFormObject()->getEntity();
    $already_uploaded_files = getUserPictureFiles($user);
    $nbre_file = count($already_uploaded_files);
    $callback = 'remove_user_picture_callback';

    if ($nbre_file < 10) {
      $form['field_photos'] = [
        '#title' => t('Vos photos'),
        '#type' => 'dropzonejs',
        '#max_files' => (10 - $nbre_file),
        '#dropzone_description' => t('Déposez les fichiers ici pour les télécharger'),
        '#attributes' => [
          'id' => 'field-photos',
        ],
      ];
      $form['photos_left'] = [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => t(10 - $nbre_file . " photo(s) restante(s)"),
        '#prefix' => '<div id="field-photos-left">',
        '#suffix' => '</div>',
      ];
    }
    if ($nbre_file === 10) {
      $form['field_photos'] = [
        '#title' => t('Vos photos'),
        '#type' => 'markup',
        '#markup' => t("Nombre maximum de photos atteint."),
      ];
    }

    if ($already_uploaded_files) {
      $form['saved_uploaded_files'] = [
        '#type' => 'value',
        '#value' => $already_uploaded_files,
        '#attributes' => ['id' => 'save-uploaded-files'],
      ];

      $form['user_pictures_container'] = [
        '#type' => 'container',
        '#attributes' => [
          'class' => ['user-photos-container'],
          'id' => ['user-photos-container'],
        ],
      ];
      foreach ($already_uploaded_files as $key => $file) {
        $form['user_pictures_container']['picture_container_' . $key] = [
          '#type' => 'container',
          '#attributes' => [
            'class' => ['image-square-container'],
            'id' => ['image-square-container-' . $file->id()],
          ],
        ];
        $form['user_pictures_container']['picture_container_' . $key]['user_uploaded_picture_' . $key] = [
          '#type' => 'html_tag',
          '#tag' => 'img',
          '#attributes' => [
            'src' => $file->createFileUrl(),
          ],
        ];
        $form['user_pictures_container']['picture_container_' . $key]['remove_picture_' . $key] = [
          '#type' => 'button',
          '#name' => 'remove-button-' . $file->id(),
          '#attributes' => [
            'class' => ['user-picture-delete-icon-field'],
            'data-name' => 'remove-button-' . $file->id(),
          ],
          '#ajax' => [
            'callback' => $callback,
            'wrapper' => 'field-photos-left',
            'effect' => 'fade',
            'event' => 'click',
            'prevent' => 'submit',
            'progress' => [
              'type' => 'throbber',
              'message' => t('Suppression de la photo...'),
            ],
          ],
        ];
      }
    }

以及内部调用函数的回调

function remove_user_picture_callback($form, FormStateInterface $form_state): AjaxResponse {

  // Get user Entity.
  $user = getUserEntity($form_state);
  // Get trigger fid.
  $fid = getFid($form_state);

  // Delete picture reference from user field_photos,
  deletePictureReference($user, $fid);

  return updateNbrePhotoUploaded($form, $form_state);
}



function updateNbrePhotoUploaded($form, FormStateInterface $form_state): AjaxResponse {
  $user = getUserEntity($form_state);
  $already_uploaded_files = getUserPictureFiles($user);
  $nbre_file = count($already_uploaded_files);

  $elem['photos_left'] = [
    '#type' => 'html_tag',
    '#tag' => 'p',
    '#value' => t(10 - $nbre_file . " photo(s) restante(s)"),
    '#prefix' => '<div id="field-photos-left">',
    '#suffix' => '</div>',
  ];

  $response = new AjaxResponse();
  $response->addCommand(new ReplaceCommand('#field-photos-left', $elem));

  return $response;
}

/**
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *
 * @return string
 */
function getFid(FormStateInterface $form_state): string {
  $element = $form_state->getTriggeringElement()['#name'];
  return substr($element, strpos($element, '-') + 8);
}

/**
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *
 * @return \Drupal\user\Entity\User
 */
function getUserEntity(FormStateInterface $form_state): User {
  $form_state_user = $form_state->getFormObject()->getEntity();
  return User::load($form_state_user->id());
}

/**
 * @param \Drupal\user\Entity\User $user
 * @param string $fid
 *
 * @return void
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function deletePictureReference(User $user, string $fid): void {
  $field_photos = $user->get('field_photos');
  $field_photos_values = $field_photos->getValue();

  // Get the index to remove
  $index_to_remove = array_search($fid, array_column($field_photos_values, 'target_id'));
  $field_photos->removeItem($index_to_remove);

  $user->save();
}

/**
 * Return array of user picture Files entity.
 *
 * @param $user
 *
 * @return array
 */
function getUserPictureFiles($user): array {
  $user_pictures = $user->get('field_photos')->getValue();
  $files = [];

  if ($user_pictures) {
    foreach ($user_pictures as $user_picture) {
      if (array_key_exists('target_id', $user_picture)) {
        /** @var File $file */
        $file = File::load($user_picture['target_id']);
        $files[] = $file;
      }
    }
  }

  return $files;
}

在这种情况下,我到处搜索相同的错误,但是...... 如果有人能帮忙! 谢谢

PHP AJAX 表单 Drupal 回调

评论

0赞 Thomas Lefetz 9/1/2022
您确定在提交时存在第二个表单字段吗?我想在表单构建中,您没有第二个表单字段。
0赞 Juju 9/11/2022
我会调查并回来。但是,如果不是这样,那么进行 Ajax 响应的好方法应该是什么?
0赞 Juju 9/16/2022
我终于让它工作了。我以单独的表格导出了导致问题的表单部分,在另一个页面上,专门用于照片管理。

答: 暂无答案