You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular文件上传点击无响应:未弹出确认弹窗问题求助

文件上传无响应排查方案

问题现象

上传界面正常显示,但点击上传按钮后无任何动作,预期弹出的“您确定吗?”确认窗口未出现。

Angular端代码检查

file-upload-component.ts

import { CommonModule } from '@angular/common';
import { HttpClientModule, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Component, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgxFileDropEntry, FileSystemFileEntry, FileSystemDirectoryEntry, NgxFileDropModule } from 'ngx-file-drop';
import { HttpClientService } from '../http-client.service';
import { AlertifyService, MessagePosition, MessageType } from '../alertify.service';
import { MatDialog } from '@angular/material/dialog';
import { FileUplaodDialogState, FileUploadDialogComponent } from '../../../dialogs/file-upload-dialog/file-upload-dialog.component';
import { DialogService } from '../dialog.service';
import { MatButton } from '@angular/material/button';

@Component({
  selector: 'app-file-upload',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    NgxFileDropModule,
    MatButton
  ],
  templateUrl: './file-upload.component.html',
  styleUrl: './file-upload.component.scss'
})
export class FileUploadComponent {

  constructor(
    private httpClient : HttpClientService,
    private alertift : AlertifyService,
    private dialog : MatDialog,
    private dialogService : DialogService
  ) 
  { }

  @Input() options : Partial<FileUploadOptions>;

  public files: NgxFileDropEntry[];

  public dropped(files: NgxFileDropEntry[]) {

    this.files = files;
    const formData = new FormData()
    for (const droppedFile of files) {
      (droppedFile.fileEntry as FileSystemFileEntry).file((file: File) => {
        formData.append(droppedFile.relativePath, file, droppedFile.relativePath)
      })
    }

    this.dialogService.openDialog({
      componentType : FileUploadDialogComponent,
      data : FileUplaodDialogState.Yes,
      afterClosed  : () => {
        this.httpClient.post({
          controller : this.options.controller,
          action : this.options.action,
          queryString : this.options.queryString,
          headers : new HttpHeaders({ "responseType" : "blob" })
        },formData).subscribe(res => {
          this.alertift.message("Dosya veya dosyalar başarıyla yüklendi", {
            messagePosition : MessagePosition.TopRight,
            messageType  : MessageType.Success
          })
        },(errorResponse : HttpErrorResponse) => {  
          this.alertift.message("Dosya veya dosyalar yüklenirken hata oluştu", {
            messagePosition : MessagePosition.TopRight,
            messageType  : MessageType.Error
          })
        })
      }
    })
  }
}

export class FileUploadOptions {
   controller? : string;
   action? : string;
   queryString? : string;
   acceptedFiles? : string;
}

select-article-image-dialog.component.ts

import { Component, Inject, OnInit, Output } from '@angular/core';
import { BaseDialog } from '../base-dialog';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FileUplaodDialogState } from '../file-upload-dialog/file-upload-dialog.component';
import {MatDialogModule} from '@angular/material/dialog';
import { MatButton } from '@angular/material/button';
import { FileUploadComponent, FileUploadOptions } from '../../services/common/file-upload/file-upload.component';

@Component({
  selector: 'app-select-article-image-dialog',
  standalone: true,
  imports: [
    MatDialogModule,
    MatButton,
    FileUploadComponent
  ],
  templateUrl: './select-article-image-dialog.component.html',
  styleUrl: './select-article-image-dialog.component.scss'
})
export class SelectArticleImageDialogComponent extends BaseDialog<SelectArticleImageDialogComponent> {

  constructor (dialogRef  : MatDialogRef<SelectArticleImageDialogComponent>, @Inject(MAT_DIALOG_DATA) public data : SelectArticleImageState | string) {
    super(dialogRef)
  } 
    

  @Output() options : Partial<FileUploadOptions> = {
    acceptedFiles : ".png,.jpg,.jpeg",
    action : "upload",
    controller : "articles",
    queryString :`id=${this.data}`
  }
}

export enum SelectArticleImageState {
  Close
}

HTML模板

<h2 mat-dialog-title></h2>
<mat-dialog-content class="mat-typography">
  
  <app-file-upload [options]="options"></app-file-upload>

</mat-dialog-content>
<mat-dialog-actions align="end">
  <button mat-button mat-dialog-close>Cancel</button>
</mat-dialog-actions>

服务端代码

[HttpPost("[action]")]
public async Task<IActionResult> Upload(string id)
{
    List<(string fileName, string pathOrContainerName)> result = await _storageService.UploadAsync("images", Request.Form.Files, _webHostEnvironment);

    await _articleImageFileWriteRepository.AddRangeAsync(result.Select(x => new ArticleImageFile()
    {
        FileName = x.fileName,
        Path = x.pathOrContainerName,
        Storage = "Local",
    }).ToList());

    await _articleImageFileWriteRepository.SaveAsync();
    return Ok();
}

排查要点

  1. 修正属性装饰器错误:SelectArticleImageDialogComponent中的options属性误用了@Output(),这会导致子组件app-file-upload无法正确接收配置参数,直接移除@Output()即可。
  2. 检查拼写错误:代码中FileUplaodDialogState存在拼写错误(缺少字母n,应为FileUploadDialogState),如果FileUploadDialogComponent中定义的枚举是正确拼写,会导致弹窗无法正确识别状态,进而不触发弹窗。
  3. 异步操作顺序问题:dropped方法中,formData的构建是在异步回调file()中完成的,此时调用dialogService.openDialog后,afterClosed回调执行时formData可能还未填充完成,需要将openDialog逻辑移到异步回调内部,或者使用Promise.all等待所有文件处理完成后再打开弹窗。
  4. 控制台报错检查:打开浏览器开发者工具的控制台,查看是否有组件未注册、依赖注入失败、模板绑定错误等信息,这些是最直接的问题线索。
  5. DialogService实现验证:确认dialogService.openDialog方法是否正确调用了MatDialog.open()来打开FileUploadDialogComponent,并且该组件已正确导入到当前模块中。

内容的提问来源于stack exchange,提问作者İbrahim Özdemir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:03:09