While working on a new ASP.NET MVC project, I had a simple objective: add a new record and refresh my View. After sifting through several sites I found several resources that lead me to accomplish my goal.
I’ve compiled my result into a new sample MVC Application that I created in Visual Studio that you can download here. I’ll explain what I did using that as my reference. It’s a trimmed down version of what I did on the actual project, but it will get the point across.
Let’s assume we want to have a View that lists some People from our data source. I started out by creating a Person data model:
public class Person
{
public Guid Id { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public Person()
{
Id = Guid.NewGuid();
}
}
Next, I created some ViewModels so that I can work with strongly typed Views:
public class PersonIndexViewModel
{
public PersonListViewModel PersonListModel { get; set; }
public AddPersonViewModel AddPersonModel { get; set; }
}
public class PersonListViewModel
{
public List PersonList { get; set; }
}
public class AddPersonViewModel
{
public String FirstName { get; set; }
public String LastName { get; set; }
}
Next, I added a People folder in my Views folder and created a strongly typed Index View on my PersonIndexViewModel. I started out with building a table and doing a foreach to display each Person object. I moved that into a PartialView (.ascx) by creating a ParitialView in my Views/Shared folder (This blog post is very helpful for showing you how to use PartialViews). I called that PersonList.ascx and that is a strongly typed partial view on my PersonListViewModel.
Now, I can update my View to display that PartialView with this code:
<% Html.RenderPartial("PersonList", Model.PersonListModel); %>
Next, I want to be able to perform a delete action to remove a Person from the DB. You’ll notice I’m using an Ajax.ActionLink in my PersonList PartialView so that I can perform the delete with Ajax.
<%= Ajax.ActionLink("delete", "JsonDelete", "People", new { Id = person.Id }, new AjaxOptions { Confirm = "Are you sure you want to Delete this Person? This action cannot be undone.", HttpMethod = "Delete", OnComplete = "JsonDelete_OnComplete" })%>
In the ActionLink, I specify the Action I want to call, pass the Person.Id and in the AjaxOptions I defined a JavaScript method that should be called on complete. In my People Controller I can now add the JsonDelete method:
[AcceptVerbs(HttpVerbs.Delete)]
public JsonResult JsonDelete(Guid Id)
{
// call your Repository to delete the Person
bool result = _personList.Remove(toDelete);
// return a Json Object, you could define a new class
return Json(new
{
Success = result,
Message = result ? "The person has been deleted!" : "Error!"
});
}
You would call your Repository to delete that Person and then return a new Json Object. What I did was define a couple of properties that I will reference from the JavaScript function to give feedback to the user. Here is the JavaScript function:
function JsonDelete_OnComplete(context) {
var JsonDelete = context.get_response().get_object();
if (JsonDelete.Success) {
$(this).parents('tr.item').remove();
}
$("#message").html(JsonDelete.Message);
}
I found this link that showed me how to use “context.get_response().get_object();” to get the Json Object in JavaScript.
Now that I can delete, the next logical step would be the ability to add a new Person. I’ll start out by creating a new form that uses my AddPersonViewModel Model:
<% using (Ajax.BeginForm("JsonAdd", "People", new AjaxOptions { OnComplete = "JsonAdd_OnComplete" })) {%> <fieldset> <legend>Add a Person</legend> <%= Html.LabelFor(model => model.AddPersonModel.FirstName)%>: <%= Html.TextBoxFor(model => model.AddPersonModel.FirstName, new { @class = "firstname" })%> <%= Html.ValidationMessageFor(model => model.AddPersonModel.FirstName)%> <%= Html.LabelFor(model => model.AddPersonModel.LastName)%>: <%= Html.TextBoxFor(model => model.AddPersonModel.LastName, new { @class = "lastname" })%> <%= Html.ValidationMessageFor(model => model.AddPersonModel.LastName)%> <input id="AddBtn" name="AddBtn" type="submit" value="Add" /> </fieldset> <% } %>
Again, I use the Ajax.BeginForm to set the Action to call and define a JavaScript function to call on complete. To my Controller I add:
public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
{
...
Person newPerson = new Person
{
FirstName = AddPersonModel.FirstName,
LastName = AddPersonModel.LastName
};
// call your Repository to add the new Person
_personList.Add(newPerson);
// return a Json Object, you could define a new class
return Json(new
{
Success = true,
Message = "The person has been added!",
PartialViewHtml = RenderPartialViewToString("PersonList", new PersonListViewModel {PersonList = _personList})
});
}
One important thing here is the method “RenderPartialViewToString”. I ran across this which was a tremendous resource in solving my problem here, which was returning a Json Object with a rendered PartialView so that I could use JavaScript/jQuery to update the page.
The post I referenced above showed where you needed to create a base Controller to inherit from and that Controller defines the methods which will return a PartialView as an HTML string:
public abstract class BaseController : Controller
{
protected string RenderPartialViewToString()
{
return RenderPartialViewToString(null, null);
}
protected string RenderPartialViewToString(string viewName)
{
return RenderPartialViewToString(viewName, null);
}
protected string RenderPartialViewToString(object model)
{
return RenderPartialViewToString(null, model);
}
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
}
Now with my JavaScript function is called, I can again reference my Json Object and then update the page:
function JsonAdd_OnComplete(context) {
var JsonAdd = context.get_response().get_object();
if (JsonAdd.Success) {
$("#PersonList").html(JsonAdd.PartialViewHtml);
}
$("#message").html(JsonAdd.Message);
}
With this line:
$("#PersonList").html(JsonAdd.PartialViewHtml);
I have a div tag that surrounds my Html.RenderPartial call and I can use jQuery to just replace the HTML. Remember JsonAdd.PartialViewHtml contains the entire HTML of the newly rendered PartialView that we called from the Controller:
return Json(new { Success = true, Message = "The person has been added!", PartialViewHtml = RenderPartialViewToString("PersonList", new PersonListViewModel {PersonList = _personList}) });
That just about sums it up how to use Ajax, jQuery, Json, and PartialViews in an effective manor in an ASP.NET MVC application.