views:

1302

answers:

4

Can I return a Json result that contains also a rendered view?

I need it to return the new ID of a submitted form along with its HTML and some other properties.

Also that can be helpful when I need to return two (or more) view results from one action inside a Json object.

Thanks!

A: 

This might be a little hacky (and I am writing of the top of my head) but you might want to create your own subclass of ActionResult and also implement a ResultFilter which would intercept these specific types of ActionResult and render the relevant Views and fill a JsonResult and return it.

For example you can define:

public CompoundResult: ActionResult
{
    public string ViewName { get; set; }
    public JsonResult JsonResult { get; set; }
    public CompoundResult(string viewName, JsonResult jsonResult)
    {
       ViewName = viewName;
       JsonResult = jsonResult;
    }
}

and then in a ResultFilter, render the relevant view and merge it into the relevant place in the JsonResult and finally return the JsonResult to the client.

Apart from all of this, you might want to change your approach in how you do this, eg. you might try returning a full view (ie HTML) from your action a part of which is the view you want to return but which also includes some extra information that would have otherwise been in your JSON object. You can take out the relevant components from the returned HTML using simple jQuery operations on the client-side.

paracycle
+1  A: 

In the first case, I think you can just return HTML, but embed the data in the returned form. Use jQuery to access the data in your success callback.

$.ajax({
    url: '<%= Url.Action( "MyAction" )',
    dataType: 'html',
    data: $('form').serialize(),
    success: function(data) {
                $('form').html(data);
                var id = $('form').find('input#formId[type=hidden]').val();
             }
});

In the second case, a shared View that takes two or more ViewNames and uses RenderPartial is probably a better solution that returning HTML through JSON.

Multiview.aspx

 ...
<% foreach (string viewName in Model.Views)
   {
       Html.RenderPartial( viewName );
   }
%>

Then in your action:

public ActionResult MyAction(...)
{
     ... set up model with data
     model.Views = new List<string> { "View1", "View2" };

     return View( "Multiview", model );
}
tvanfosson
+2  A: 

You can also render a PartialViewResult to a string, and then pass this string via JSON to your view, rendering it in your page using jQuery.

You can see that in this post: http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/.

I've created an extension to make it easier:

public static class MvcHelpers
{
    public static string RenderPartialView(this Controller controller, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = controller.ControllerContext.RouteData.GetRequiredString("action");

        controller.ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }
}

In my controller I call it as follows:

const string msg = "Item succesfully updated!";
return new JsonResult
           {
               Data = new
                          {
                              success = true, 
                              message = msg,
                              view = this.RenderPartialView("ProductItemForm", model)
                          },
               JsonRequestBehavior = JsonRequestBehavior.AllowGet
           };

Where "this" is the controller in the case, "ProductItemForm" is my view and "model" is my productItem object :)

Hope this helps ;)

Diego Ponciano
A: 

I've been thinking about this problem for a while. My solution is similar to returning the partial view HTML as a JSON string, but the opposite. Return a partial view with JSON embedded in it. I did not like this approach until jQuery 1.4.3 merged their .data() method with the HTML 5 data attribute. This makes it much easier to generate JSON within a ASP.NET MVC view, and read it via jQuery.

See example... It isn't perfect, but I like it much better than creating hidden form inputs or helpers that render the partial view before returning it.

Partial View:

<div id="content">
  <h1>Some Title</h1>
  <p>Ipsum Lorem</p>
</div>
<div id="dataDiv" data-stuff='{ "name": "Jason", "color": "Blue"}'></div>

JavaScript that reads the JSON

$(document).ready(function () {
  var name = $('#dataDiv').data('stuff').name;
  var color = $('#dataDiv').data('stuff').color;
  alert(name + ' ' + color);
});

This may appear to go against the "single responsibility principle" (if you apply it to views). However, if your application requires both pieces of data to be transmitted in a response, then I see nothing wrong with it. And as long as your model is constructed properly, it won't go against any design principles.

Jason Capriotti