I'd like to know how to upload a file using angular and form builder, currently I have only found tutorials using formbuilder with a single file like this File Upload In Angular?
My problem is with the .ts
file, how do you append the file to a field in formbuilder? I've seen it done with formData()
but can't get them both to work together, any hints are very appreciated!
component.ts
ngOnInit() {
this.escolaridad_candidato = this.fb.group({
nivel_estudio: [, [Validators.required]],
escuela: [, [Validators.required]],
graduacion: [, [Validators.required]],
certificado: [, [Validators.required]] <--This is the file I need to append
});
}
onEstudiosChange(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = () => {
this.exp_academica.patchValue({
certificado: reader.result
});
// need to run CD since file load runs outside of zone
this.cd.markForCheck();
};
}
}
// On Submit button
this.myservice.post('myUrl', this.escolaridad_candidato.rawdata(), configOptions )
component.html
<form [formGroup]="escolaridad_candidato" >
<div class="col s6 center-align" >
<p >Estudios</p>
<div class="row">
<div class="col s12">
<p >Degree</p>
<select class="browser-default" formControlName="nivel_estudio">
<option value="" disabled selected>----</option>
<option *ngFor="let nivel of listnivelEstudios" value="{{ nivel.id }}">
{{ nivel.nombre }}
</option>
</select>
</div>
<div class="col s12 center-align input-field">
<p >Escuela </p>
<input id="escuela" type="text" class="validate browser-default" formControlName="escuela"/>
</div>
<div class="col s12 input-field center-align">
<p >Año de graduación </p>
<input id="graduacion" type="text" class="validate browser-default"
formControlName="graduacion" />
</div>
</div>
<div class="row">
<div class="col s12">
<p >Certificate </p>
<div class="file-field input-field">
<div class="btn" >
<span>Adjuntar archivo +</span>
<input type="file" formControlName="certificado" (change)="onEstudiosChange($event)">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text">
</div>
</div>
</div>
</div>
</div>
</form>
It's weird there's so little documentation on how to do this.
The answer was relatively simple:
the html must have an input like this
<input type="file" (change)="onFileChanged($event, i)">
Using fb you can extract the values of your form with something like
const myFormValue = this.myForm.value
In the .ts file:
public onFileChanged(event: any) {
if (event.target.files && event.target.files.length) {
const file = event.target.files[0];
this.certEscolar = file;
}
}
submit() {
const myFormValue = this.myForm.value
const myFormData = new FormData();
for ( let i = 0; i < myFormValue.length; i++ ) {
for ( let key of myFormValue) {
myFormData.append(key, myFormValue[key]);
}
}
this.http.post<any>(SOMEURL, myFormData, Config.api.multiContentOptions)
.subscribe(response => {
console.log("response from server!", response)
}
The headers I used were:
Config.ts
const MultipartHeaders: HttpHeaders = new HttpHeaders({
Authorization: 'Token ' + token,
Accept: 'application/json'
});
let Config = {
api: {
baseURL: 'http://11.98.155.150/back/ws' //obviously fake
options: { headers: jsonheaders },
formatOptions: { headers : formDheaders },
multiContentOptions: { headers : MultipartHeaders },
}
};
It gets a lot trickier with formArrays and FormData, if anyone requests I can upload an example.