2

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>
10
  • Hello Jaime. Could you please tell me the version of angular that you are using? Commented Mar 9, 2019 at 7:12
  • I am using angular 7, sorry for the delay. Do you think this still works? Commented Mar 9, 2019 at 20:17
  • I fear I will have to rework on that part and I am about to crash at the moment🤣. I shall revert back with a new solution tomorrow. Commented Mar 9, 2019 at 20:20
  • Thanks a lot for the help! Commented Mar 9, 2019 at 20:20
  • No problem Jamie anytime :). Commented Mar 9, 2019 at 20:22

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

I have specified code for both Angular 7 and any version less than 7 but greater than 2.

            formDataProductImagePost(endPoint, formData) {
               let headers = new Headers();
               let formDataFinal = new FormData();

               // The below for loop is for multiple file uploads. If you have only one file which needs to be uploaded then you don't need the loop.
               for (let j = 0; j < formData.length; j++) {
                    formDataFinal.append('file', formData[j]);
               }
               return this.http.post(this.profileApiUrl + endPoint, formDataFinal, {
                    headers: headers
               }).toPromise().then((response: any) => {
                    let image_id = JSON.parse(response._body)['response'];
                    // console.log(image_id);
                    return image_id;
               });
            }




/// This shall work on Angular 7. Let me know if you face any issues :).

 <form [formGroup]="myForm">
    <div class="form-group form-inline">
      <label class="btn btn-secondary btn-file">Browse
       <input name="file" type="file" (change)="onFileChange($event)">
       <input type="hidden" name="fileHidden" formControlName="file"/>        
       <!-- Validation Field -->
   </label>

    <p *ngIf="file" class="pl-4 align-middle mb-0">{{file.name}}</p>
  </div>
  <button type="button" class="btn btn-primary" (click)="finalUpload()">Upload</button>
</form>


// Angular Code
   public file: string = '';
   public fileN = new FormControl();

   ngOnInit() {
            let self = this;
            this.myForm = this.formBuilder.group({
                  fileN: [fileName, Validators.required]
            });

    }

   finalUpload() {
            this.uploadData().subscribe(data => {
                    console.log(data);
            });
    }

    uploadData():Observable<any> {
            let formData  = new FormData();
            let result = Object.assign({}, this.myForm.value);
            for (let o in result) {
                    formData.append(o, result[o])
            }
            return this.request.post<any>('http://localhost:8000/api/image', formData);
    }

    handleError(error: any) {
            return error;
            // console.log(error);
    }

    onFileChange($event) {
            this.file = $event.target.files[0]; // <--- File Object for future use.
            let file = $event.target.files[0]; // <--- File Object for future use.
            this.myForm.controls['fileN'].setValue(file ? file.name : ''); // <-- Set Value for Validation
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.