Angular 7 : 我如何提交 file/image 以及我的反应形式?
Angular 7 : How do I submit file/image along with my reactive form?
我已经使用文本输入创建了简单的响应式表单,并且在提交表单时我想传递来自文件输入的图像。每次我 google 我都会得到教程,在那里他们告诉我如何上传文件,但它是在没有其他输入字段的情况下完成的。我知道该怎么做,但我不明白如何在一次提交中同时提交我的表单和文件输入。
在我的场景中,我不应该使用反应式表单而是简单的 new FormData()
并将每个输入附加到其中吗?
如果我能做到,给我一个简单的例子。
编辑: 这不是答案。答案市场没有随反应形式发布文件,它是单独发布文件。
文件是二进制数据,表单字段通常是json文本文件。为了将它们合二为一 post,您必须将其中一个数据转换为另一个数据。我通过将文件转换为 base64 字符串,然后将其添加到普通 json 数据来做到这一点。显然,您必须将 base64 字符串转换回文件,但大多数环境(例如 C#)都可以开箱即用。
这里有一些代码可以向您展示我是如何做到的:
Html(这是文件按钮,你必须使用它来让你的浏览器允许你从文件系统select一个文件):
<input name="imageUrl" type="file" [accept]="filePattern" multiple=""
(change)="handleInputChange($event)" />
.ts:
handleInputChange(e) {
const file = e.dataTransfer ? e.dataTransfer.files[0] : e.target.files[0];
const reader = new FileReader();
const fileDto: Partial<IFileSaveDto> = {
// your other data here
title: 'what ever here',
fileAsBase64: null
};
reader.onload = (ev: ProgressEvent) => {
fileDto.fileAsBase64 = reader.result;
};
reader.readAsDataURL(file);
}
该方法的缺点是 base64 会产生相当大的开销。如果您上传的文件很大或很多,那不是一个好方法。
这是一个完整的解释示例:https://nehalist.io/uploading-files-in-angular2/
也有这个问题,我做的是构建一个FormData,使用循环将formGroup值添加到表单Data
import {
Component,
OnInit,
ChangeDetectorRef
} from '@angular/core';
import {
FormGroup,
FormBuilder,
Validators
} from '@angular/forms';
export class TodoFormComponent {
todoForm: FormGroup = this.fb.group({
todo: ['', Validators.required],
image: ['', Validators.required], //making the image required here
done: [false]
})
constructor(
private fb: FormBuilder,
private cd: ChangeDetectorRef
) {}
/**
*@param event {EventObject} - the javascript change event
*@param field {String} - the form field control name
*/
onFileChange(event, field) {
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
// just checking if it is an image, ignore if you want
if (!file.type.startsWith('image')) {
this.todoForm.get(field).setErrors({
required: true
});
this.cd.markForCheck();
} else {
// unlike most tutorials, i am using the actual Blob/file object instead of the data-url
this.todoForm.patchValue({
[field]: file
});
// need to run CD since file load runs outside of zone
this.cd.markForCheck();
}
}
onSubmit() {
const formData = new FormData();
Object.entries(this.todoForm.value).forEach(
([key, value]: any[]) => {
formData.set(key, value);
}
//submit the form using formData
// if you are using nodejs use something like multer
)
}
}
<form [formGroup]="todoForm" (ngSubmit)="onSubmit()">
<input type="file" formControlName="image" (onchange)="onFileChange($event, 'image')"/>
<textarea formControlName="todo"></textarea>
<button type="submit">Submit</button>
</form>
在服务器端,您可以像处理表单数据请求一样处理请求
我已经使用文本输入创建了简单的响应式表单,并且在提交表单时我想传递来自文件输入的图像。每次我 google 我都会得到教程,在那里他们告诉我如何上传文件,但它是在没有其他输入字段的情况下完成的。我知道该怎么做,但我不明白如何在一次提交中同时提交我的表单和文件输入。
在我的场景中,我不应该使用反应式表单而是简单的 new FormData()
并将每个输入附加到其中吗?
如果我能做到,给我一个简单的例子。
编辑:
文件是二进制数据,表单字段通常是json文本文件。为了将它们合二为一 post,您必须将其中一个数据转换为另一个数据。我通过将文件转换为 base64 字符串,然后将其添加到普通 json 数据来做到这一点。显然,您必须将 base64 字符串转换回文件,但大多数环境(例如 C#)都可以开箱即用。
这里有一些代码可以向您展示我是如何做到的:
Html(这是文件按钮,你必须使用它来让你的浏览器允许你从文件系统select一个文件):
<input name="imageUrl" type="file" [accept]="filePattern" multiple=""
(change)="handleInputChange($event)" />
.ts:
handleInputChange(e) {
const file = e.dataTransfer ? e.dataTransfer.files[0] : e.target.files[0];
const reader = new FileReader();
const fileDto: Partial<IFileSaveDto> = {
// your other data here
title: 'what ever here',
fileAsBase64: null
};
reader.onload = (ev: ProgressEvent) => {
fileDto.fileAsBase64 = reader.result;
};
reader.readAsDataURL(file);
}
该方法的缺点是 base64 会产生相当大的开销。如果您上传的文件很大或很多,那不是一个好方法。
这是一个完整的解释示例:https://nehalist.io/uploading-files-in-angular2/
也有这个问题,我做的是构建一个FormData,使用循环将formGroup值添加到表单Data
import {
Component,
OnInit,
ChangeDetectorRef
} from '@angular/core';
import {
FormGroup,
FormBuilder,
Validators
} from '@angular/forms';
export class TodoFormComponent {
todoForm: FormGroup = this.fb.group({
todo: ['', Validators.required],
image: ['', Validators.required], //making the image required here
done: [false]
})
constructor(
private fb: FormBuilder,
private cd: ChangeDetectorRef
) {}
/**
*@param event {EventObject} - the javascript change event
*@param field {String} - the form field control name
*/
onFileChange(event, field) {
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
// just checking if it is an image, ignore if you want
if (!file.type.startsWith('image')) {
this.todoForm.get(field).setErrors({
required: true
});
this.cd.markForCheck();
} else {
// unlike most tutorials, i am using the actual Blob/file object instead of the data-url
this.todoForm.patchValue({
[field]: file
});
// need to run CD since file load runs outside of zone
this.cd.markForCheck();
}
}
onSubmit() {
const formData = new FormData();
Object.entries(this.todoForm.value).forEach(
([key, value]: any[]) => {
formData.set(key, value);
}
//submit the form using formData
// if you are using nodejs use something like multer
)
}
}
<form [formGroup]="todoForm" (ngSubmit)="onSubmit()">
<input type="file" formControlName="image" (onchange)="onFileChange($event, 'image')"/>
<textarea formControlName="todo"></textarea>
<button type="submit">Submit</button>
</form>
在服务器端,您可以像处理表单数据请求一样处理请求