I am working on a side project to teach myself AngularJS and Web API and how the two can work together nicely.
I have good ASP.NET MVC knowledge, but I still can't get my head around AngularJS and Web API and how all three can work together.
At the moment, I have a Web API Controller with the following code:
public class PlanController : ApiController
{
[Route("api/thing")]
public HttpResponseMessage Post(ThingVM model)
{
HttpResponseMessage response;
if (ModelState.IsValid)
{
using (var context = new MyContext())
{
var thing = new Thing();
context.Thing.Add(thing);
context.SaveChanges();
response = Request.CreateResponse(HttpStatusCode.Created);
string uri = Url.Link("GetThingById", new {id = thing.Id});
response.Headers.Location = new Uri(uri);
}
}
else
{
response = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return response;
}
}
In my Create.cshtml
view I have the ng-app
directive and I have created a JS controller and placed the ng-controller
directive around the form, and have pointed it at the JS controller.
But here I am stuck. First of all, how do I bind my ThingVM.cs
ViewModel to Angular? Do I need to return a JSONResult
on my MVC controller? If Yes, how? Cause I tried, the following, and it isn't compiling.
[HttpGet]
public JsonResult Create()
{
using (var context = new MyContext())
{
var model = new ThingVM();
return Json(model);
}
}
Assuming I get that to work, how do I bind it to AngularJS, so that it knows what my ViewModel structure is like? Because my ThingVM
has many levels of complexity.
Finally, how do I handle the form submission, so that angular points at my Web API Controller for the POST
request.
In MVC SPA like angular, you should separate models from views. I would suggest that your asp.mvc is where you serve your views (HTML) and your asp.net web api is where you serve your models (JSON) with CRUD operations.
Your asp.net mvc controller:
[HttpGet]
public ActionResult Create()
{
return View(); //this return Create.cshtml
}
Your asp.net api controller:
public class PlanController : ApiController
{
public ThingVM Get()
{
using (var context = new MyContext())
{
var model = new ThingVM();
return model;
}
}
public HttpResponseMessage Post(ThingVM model)
{
HttpResponseMessage response;
//It's better to write the modelstate validation as an attribute. See improvement suggestion below
if (ModelState.IsValid)
{
using (var context = new MyContext())
{
var thing = new Thing();
context.Thing.Add(thing);
context.SaveChanges();
response = Request.CreateResponse(HttpStatusCode.Created);
string uri = Url.Link("GetThingById", new {id = thing.Id});
response.Headers.Location = new Uri(uri);
}
}
else
{
response = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return response;
}
}
Your angular controller, here I use $http
for quick demonstration. In real app, you could try angular resource to create a REST client
app.controller("planController", function ($scope, $http){
$scope.thingVM = $http.get("api/Plan"); //load view model as json from web api
$scope.saveThingVM = function(){
http.post("api/Plan",$scope.thingVM); //send a post request to web api to update
}
});
Your Create.cshtml
could be like this:
<form ng-submit="saveThingVM()" ng-controller="planController">
<input ng-model="thingVM.Name" type="text"></input>
<input type="submit">Save model</input>
</form>
Improvement suggestion:
Model validation is a cross-cutting concern, it's better to write the logic as an attribute to reuse the logic. Take a look at my another answer at How can I centralize modelstate validation in asp.net mvc using action filters?