Atlantic Business Technologies, Inc.

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.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *