1

I have a somewhat complex form with two nested FormGroup. Each nested FormGroup containing a file input field along with other 6 input fields as Follows:

In the Component:

updateEmployeeNomineeForm: FormGroup;

ngOnInit() {
   this.updateEmployeeNomineeForm = this.formBuilder.group({
      employeeNominee1: this.formBuilder.group({
        employeeId: [employeeId],
        nomineeName: [],
        nomineeRelation: [],
        nomineeContactNo: [],
        nomineeNationalId: [],
        nomineePicture: [], // This is the file input
        additionalInfo: []
      }),
      employeeNominee2: this.formBuilder.group({
        employeeId: [employeeId],
        nomineeName: [],
        nomineeRelation: [],
        nomineeContactNo: [],
        nomineeNationalId: [],
        nomineePicture: [], // This is the file input
        additionalInfo: []
      })
    });
  }

And the HTML form is as like as follows:

<div *ngIf="updateEmployeeNomineeForm">
    <form [formGroup]="updateEmployeeNomineeForm" (ngSubmit)="updateEmployeeNominees()">
      <div class="row">
        <div class="col-md-6">
          <div class="card">
            <div class="card-header">
              <strong>Nominee-1</strong>
            </div>
            <div formGroupName="employeeNominee1" class="card-body">

             //Other inputs omitted for Clarity

              <div class="form-group row">
                <label class="col-md-4 col-form-label">Nominee Picture</label>
                <div class="custom-file col-md-8">
                  <input type="file"  #nomineePicture1 formControlName="nomineePicture" class="form-control">
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="col-md-6">
          <div class="card">
            <div class="card-header">
              <strong>Nominee-2</strong>
            </div>
            <div formGroupName="employeeNominee2" class="card-body">

              //Other inputs omitted for Clarity

              <div class="form-group row">
                <label class="col-md-4 col-form-label">Nominee Picture</label>
                <div class="custom-file col-md-8">
                  <input type="file" #nomineePicture2 formControlName="nomineePicture" class="form-control">
                </div>
              </div>

            </div>
          </div>
        </div>
      </div>
      <br />
      <div class="text-center">
        <button type="submit" [disabled]="!updateEmployeeNomineeForm.valid" class="btn btn-success text-white"><i class="fa fa-floppy-o" aria-hidden="true"></i> Submit</button>

    </form>

  </div>

Now the updateEmployeeNominees() method in the Component as follows:

updateEmployeeNominees(): void {
    this.employeeService.updateEmployeeNominees(this.updateEmployeeNomineeForm.value).subscribe((updateStatus) => {
      if (updateStatus) {
        this.resetUpdateEmployeeNominees();
        this.updateSuccessMessage = "Employee Nominees updated successfully!";
        setTimeout(() => {
          this.updateSuccessMessage = null;
        }, 4000);
      }
    }, (error) => {
      this.serverErrorMessage = this.errorMessageService.getServerErrorMessageText();
    });
  }

Now the updateEmployeeNominees() method in the EmployeeService as Follows:

updateEmployeeNominees(employeeNominees: any): Observable<any> {
    const body = JSON.stringify(employeeNominees);
    const headerOptions = new HttpHeaders({ 'Content-Type': 'application/json' });
    return this.http.put<any>(this.baseUrl + 'UpdateEmployeeNominees/'+ employeeId, body, {
      headers: headerOptions
    }).catch(this.handleError);
  }

In the ASP.NET Core Web Api Controller:

[HttpPut("{id}")]
public async Task<IActionResult> UpdateEmployeeNominees([FromRoute] int id,[FromBody] EmployeeNomineesViewModel employeeNominees)
{
            //Necessary operation goes here
            return Ok(true);
}

Everything works as expected except the nomineePictures upload..Would anybody help me to bind the image files to the input field while posting the form to ASP.NET Web API controller method.

TanvirArjel
  • 30,049
  • 14
  • 78
  • 114

2 Answers2

0

you cannot get image directly.To get the image you have to some workaround.Add (change) event to input

In your html

<div class="custom-file col-md-8">
                  <input type="file" (change)="getfile($event)" formControlName="nomineePicture" class="form-control">
                </div>

In ts file

public file: File;

getfile(e: any) {

  const fileList: FileList = e.target.files;
        this.file = fileList[0];

}

updateEmployeeNominees(): void {

console.log(this.file); // this will give you the file
console.log(this.updateEmployeeNomineeForm.value); this will give you formdata

}
Arun Kumaresh
  • 6,211
  • 6
  • 32
  • 50
0

Use the native browser FileReader to read the contents of a file. Heavy disclaimer: none of this code is tested, I just wrote it out of the hat in notepad. You should get the idea if copypaste doesn't work, and intellisense will help with the rest. ;D

Template

<input #fileInput type="file"/>

component.ts

@ViewChild('fileInput') fileInput: ElementRef;
get files() {
    return this.fileInput.nativeElement.files;
}
async submit() {
    if (!this.files.length) {
        console.error('Please select a file');
        return;
    }
    const fileContents = (await Promise.all(
        this.files.map(file => this.readFile(file))
    ).map(dataUrl => this.stripDataUrl(dataUrl));
    // Each item in FileContents is now a Base64 encoded string.
    // Post 'em to server and convert them there to a blob for saving as a file, or whatever you like.     
    // If you want to know the MIME type before posting, 
    // scrap that stripDataUrl() method and extract mime from the dataUrl.
    // DataUrls are formatted like 'data:image/png;base64,xxxxxxzzz'
}

/**
 *  @return a string without the encoding type and mime
 */
stripDataUrl(dataUrl) {
    return dataUrl.split(',')[1];
}

readFile(file) {
    return new Promise((resolve, reject) => {
        var reader = new FileReader();
        reader.onload = (e: any) => {
            resolve(e.target.result);
        };
        reader.readAsDataURL(file);
    });
}

You can also show a preview of a selected image:

Template

<img *ngIf="(thumb$|async); let thumb" [src]="thumb" class="thumbnail" />

component.ts

thumb$: Observable<string>;
ngOnInit() {
    this.thumb$ = Observable.fromEvent(this.fileInput.nativeElement, 'change')
        .filter(event => !!event.target.files.length)
        .switchMap(event => Observable.fromPromise(this.readFile(event.target.files[0])))
        .filter(dataUrl => /image/i.test(dataUrl));
}
funkizer
  • 4,626
  • 1
  • 18
  • 20