Skip to content
Article

ASP.NET MVC: Using Ajax, Json, PartialViews (cnt’d)

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.

The Atlantic BT Manifesto

The Ultimate Guide To Planning A Complex Web Project