Nick koloss
Nick koloss

Reputation: 33

How to send data to an ASP.NET Controller with Angular2

I have a controller that has a Create action. Its purpose is to receive a name and data from file form, and IndexViewModel return IEnumerable<File> files.

public class HomeController : Controller
{
    static List<Models.File> files = new List<Models.File>();

    public HomeController() { }

    [HttpGet]
    public IActionResult Index() => View(new IndexViewModel { Files = files });

    [HttpGet]
    public IActionResult Create() => View();

    [HttpPost]
    public IActionResult Create(IFormFile file)
    {
        var filename = 
            ContentDispositionHeaderValue.Parse(file.ContentDisposition)
                                         .FileName;

        using (var reader = new StreamReader(file.OpenReadStream()))
        {
            var content = reader.ReadToEnd();
            files.Add(new Models.File { Name = filename, Data = content });
        }

        return RedirectToAction(nameof(Index));
    }
}

When I use a form in static html, it's alright, the server receives the data. But when I use the same form in an Angular2 template it doesn't.

import {Component} from 'angular2/core';
import {File} from './file';


@Component({
    selector: 'listfile',
    template: `
<form method="post" asp-action="Index" asp-controller="Api/File" enctype="multipart/form-data">
    <input type="file" name="files" #newFile (keyup.enter)="addFile(newFile.value)"
    (blur)="addFile(newFile.value); newFile.value='' ">
    <input type="submit" value="Upload" />
</form>
    <table class="table">
        <th>id</th><th>name</th>
        <tr *ngFor="#file of files"> 
            <td>{{file.id}}</td>
            <td>{{file.name}}</td>
        </tr>
</table>
    `
})
export class ListFileComponent {
    files = [
        new File(1, 'file1'),
        new File(2, 'file2')
    ];
    addFile(newFile: string) {
        if (newFile) {
            this.files.push(new File(this.files.length + 1, newFile.split(/(\\|\/)/g).pop()))
        }
    }
    falert(value) {
        alert(value);
    }
}

Upvotes: 3

Views: 4200

Answers (1)

David Pine
David Pine

Reputation: 24535

You have a misconception of the Angular2 templating and the MVC pre-processing. Here is a post that might clear that up. You have ASP.NET tag helpers that will not be rendered on the server, and instead will be sent to the client as is.

You are using the form post which passes form data, instead you should be using the Web API with Angular2's Http service.

You have many options, but two of them are the most practical at this point:

  1. You can choose to use the power of MVC for its pre-processing and have a partial view return the form. In your component you use the templateUrl instead of the template and point to the /controller/action that would pre-process the tag helpers and return the HTML as desired (this would then serve as an Angular2 template.
  2. You can start leveraging Angular2 as a true SPA, and only use MVC to serve a single page ever... /home/index. Then you use the templateUrl to point to local .html files that serve as the template. And build out an API that will support all the interactions you need.

I hope this clears things up!


If you are going to use the inline or the static .html you'll need to remove the ASP.NET tag helpers.

@Component({
    selector: 'listfile',
    template: `
<form (submit)="" >
    <input type="file" name="files" #newFile (keyup.enter)="addFile(newFile.value)"
    (blur)="addFile(newFile.value); newFile.value='' ">
    <input type="submit" value="Upload" />
</form>
    <table class="table">
        <th>id</th><th>name</th>
        <tr *ngFor="#file of files"> 
            <td>{{file.id}}</td>
            <td>{{file.name}}</td>
        </tr>
</table>
    `
})
export class ListFileComponent {
    // ...
    constructor(private http: Http) { }
    onSubmit() {
       const body = JSON.stringify({ this.files });
       this.http
           .post('api/file/create', 
                 body, 
                 { headers: new Headers({ "Content-Type": "application/json" }) })
           .map(response => response.json())
           .subscribe(json => { /* handle it */ });
    }
}

Then you'd have to change your API signature to more accurately accept the data.

Upvotes: 4

Related Questions