1

How can I send a form with an input type file to asp.net core controller, all at once, using Angular?

my template:

<form [formGroup]="form" (ngSubmit)="onSubmit()" enctype="multipart/form-data"> 
      <input placeholder="User name" type="text" formControlName="userName"/>
      <input placeholder="Email" type="text" formControlName="email"/>
      <input type="file" formControlName="file">

      <button type="submit">Salvar</button>
</form>

Component file:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { UserService } from 'app/shared/services/user/user.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-my-account',
  templateUrl: './my-account.component.html',
  styleUrls: ['./my-account.component.scss']
})
export class MyAccountComponent implements OnInit  {

  form = this.fb.group(
    {
      id: [null],
      userName: [{ value: null, disabled: true }],
      email: [null, Validators.required],
      file: [null]
    }
  );

  constructor(
    private fb: FormBuilder,
    private userServices: UserService,
    private router: Router
  ) {
  }

  ngOnInit() {

    this.userServices.getCurrentUser().subscribe( x => {
      this.form.patchValue(x);
    });
  }

  onSubmit() {
    this.userServices.update(this.form.getRawValue()).subscribe( () => {
      this.router.navigate(['/']);
    });
  }

}

UserServices

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from 'app/models/authentication/user';

@Injectable({ providedIn: 'root' })
export class UserService {
    constructor(private http: HttpClient) { }


    getCurrentUser(): Observable<User> {
      return this.http.get<User>('/Users/GetCurrentUser');
    }

    update(user: User) {
        return this.http.post('/users/update', user);
    }

}

User class:

export class User {
    id: string;
    userName: string;
    email: string;
    file: File;
    token: string;
}

and the controller:

[HttpPut]
public async Task<IActionResult> Update([FromBody]ViewModels.Account.EditViewModel viewModel, IFormFile file)
{
    if (ModelState.IsValid)
    {
        if (file != null)
        {
            var path = Path.Combine(hostEnvironment.WebRootPath, "datafiles", "images", "users");
            model.Logo = FileUploadUtils.SaveToServer(path, file, new string[] { "jpg", "jpeg", "png" });


        ....

The file parameter in the controller is always null.

What am I missing?

2 Answers 2

2

You must send a file using a multipart mime type as another rest endpoint. To achieve that on the front end side, use FormData object.

const file = input.files[0]; // data from input file
const formData = new FormData();
formData.append('file', file);

// In service
updateUserFile(formData: FormData) {
    return this.http.post('/users/update', formData);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Are you saying that I need two actions in my user controller? First one to update user data and another one to update the image ?
yeah, first for uploading your file content and second for updating your user. In common cases, backend service has a File Entity to store only files and recognize them by ID. Next, you can use FileId inside each entity required a file.
0

Remove the IFormFile file from the controller method parameters , and define it into your ViewModelClass EditViewModel

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.