在前端,我使用angular6,并且我有这种形式,您可以通过将文件拖放到div
或单击div
打开文件选择器来选择图像。
表格为
<form [formGroup]="imageUpload" (ngSubmit)="imageUploadSubmitted($event.target)" >
<div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop></div>
<input type="file" (change)='imageChange($event)' #imageInput id="imageInput" name = 'imageInput' accept=".png, .jpg, .jpeg, .gif" formControlName="imageInput" required >
<button type="submit" >Submit</button>
</form>
这是打字稿
selectedFile:File=null;
allowDrop(e) {
e.preventDefault();
}
drop(e) {
e.preventDefault();
this.imageUpload.controls.imageInput.reset();
this.selectedFile = e.dataTransfer.files[0];
let input = this.imageUpload.controls.imageInput as any;
input.value = e.dataTransfer.files[0];
}
imageChange(e){
this.selectedFile = e.target.files[0];
}
因此,在拖放图像时,请从事件中获取图像并将其放入文件输入中。提交表单后,将表单数据发送到服务以进行过帐。 无论您是从文件选择器中选择图像,还是在console.log
中放置了一个图像,__proto__ : File
都会显示一个文件对象(div
)。
imageUploadSubmitted(form){
console.log('imageInput value - ', this.imageUpload.controls.imageInput.value);
this.mapcmsService.uploadImage(form).subscribe((data) =>{
if(data.success){ alert('all good'); }
else{ alert('error'); }
})
}
该服务获取表单控件并构建一个FormData
对象以发送节点。
uploadImage(data){
let formData = new FormData(data);
let headers = new Headers();
headers.append('Authorization',this.userToken);
return this.http.post('http://localhost:3000/user/upload/image', formData ,{headers:headers} ).pipe(map(res => res.json()));
}
在节点中,我使用强大的功能来获取文件并保存。这是用于测试。
var form = new formidable.IncomingForm();
form.parse(req);
form.on('file', function (name, file){
console.log('file' , file);
});
问题是,如果我通过文件选择器选择了图像,则会得到image/jpeg
类型的文件,其名称为路径和大小。
如果我通过拖放选择图像,则会得到application/octet-stream
类型的文件。这没有名称,也没有大小。
在两种情况下我都希望获得image/jpeg
。我很困惑,这是节点还是角度问题?我怎样才能解决这个问题 ?
谢谢
角6,节点8.11.1,强大的1.2.1
答案 0 :(得分:3)
问题在于drop事件中的赋值实际上未设置输入的值,因为Angular反应形式不支持文件输入。我在说这行:
let input = this.imageUpload.controls.imageInput as any;
input.value = e.dataTransfer.files[0];
因此,当您处理案件时,实际上并没有将文件发送到服务器。这就是为什么您得到的数据是错误的。这也是指向其他两个有关响应式表单和文件上传的堆栈溢出问题的链接,其中有关于此问题的更多信息。
有两种可能的方法来解决此问题。首先是通过使用ElementRef
查询来获取文件输入的ViewChild
。然后将文件直接分配给本地html元素。这种方法的好处是,您还将在文件输入中看到删除的文件名。不利的一面是,这可能不适用于所有浏览器。 MDN上的官方文档说它可以在现代浏览器中运行,但对我来说,它可以在Chrome中运行,而不能在Edge中运行。
这是代码示例:
@ViewChild('imageInput') private imageInput: ElementRef;
public drop(e: DragEvent) {
e.preventDefault();
this.imageUpload.controls.imageInput.reset();
this.selectedFile = e.dataTransfer.files[0];
this.imageInput.nativeElement.files = e.dataTransfer.files;
}
另一种方法是,通过在代码中将所选文件自己添加到服务器之前自己添加它来自己构建FormData对象。这应该可以在任何地方正常工作。这是示例代码:
let formData = new FormData();
formData.append('imageInput', this.selectedFile);
我还创建了一个StackBlitz示例,您可以在其中查看所有代码。