2009-04-16 11 views
2

Ich mache einen AJAX-Aufruf (mit jQuery), um eine PartialView abzurufen. Zusammen mit dem HTML möchte ich eine JSON-Darstellung des Objekts, das die Ansicht anzeigt, zurücksenden. Der beschissene Weg, den ich benutzt habe, ist die Einbettung von Eigenschaften als versteckte Eingaben in den HTML-Code, der schnell unhandlich wird und eng zu viel zusammenhält.Zurückgeben einer PartialView mit HTML und JavaScript

Ich könnte nur die JavaScript in einem <script> Tag nach dem HTML senden, aber ich bin wirklich anal darüber, diese Dinge getrennt zu halten. Das würde so aussehen:

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<Person>" %> 
<div class="person"> 
    First Name: <%= Html.TextBox("FirstName", Model.FirstName) %> 
    Last Name: <%= Html.TextBox("LastName", Model.LastName) %> 
</div> 
<script type="text/javascript"> 
    // JsonSerialized object goes here 
</script> 

Eine weitere Option I ist als einen zweiten AJAX-Aufruf zu einer Aktion zu machen, die JsonResult zurückkehrt, aber das fühlt sich auch so schlechtes Design.

+0

Mit was sind Sie am Ende gegangen? Ich habe das gleiche Problem jetzt. – Jon

+0

@swilliams, könnten Sie den jQuery-Code veröffentlichen, der die Teilansicht abruft. Ich bin interessiert zu sehen, wie es gemacht wird. Danke – Picflight

+0

@Picflight - das gleiche wie Sie eine normale Ansicht und die $ .post() oder $ .ajax() Funktionen. Der Trick besteht darin, nur eine Teilansicht in der Aktion zurückzugeben.Aus der Perspektive von jQuery, einer HTML-Antwort, ist das das Gleiche. Meine "echte" Lösung ist unten. – swilliams

Antwort

2

Ich glaube, ich einen ziemlich guten Weg gefunden, dies zu tun, wickelt nur die JSON up in einer HtmlHelper Erweiterung. Hier ist die Klasse:

using System.Web.Script.Serialization; 

public static class JsonExtensions { 
    public static string Json(this HtmlHelper html, string variableName) { 
     return Json(html, variableName, html.ViewData.Model); 
    } 

    public static string Json(this HtmlHelper html, string variableName, object model) { 
     TagBuilder tag = new TagBuilder("script"); 
     tag.Attributes.Add("type", "text/javascript"); 
     JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); 
     tag.InnerHtml = "var " + variableName + " = " + jsonSerializer.Serialize(model) + ";"; 
     return tag.ToString(); 
    } 
} 

Und Sie nennen es über:

<%= Html.Json("foo") %> 
<%= Html.Json("bar", Model.Something) %> 

Die einen Haken, die ich denken kann, ist, dass es nicht eine völlig perfekte Trennung ist; Sie fügen JavaScript immer noch technisch in den HTML-Code ein. Aber, es macht keinen zusätzlichen Aufruf an den Server, und das Markup in der IDE ist immer noch sehr sauber.

1

Wahrscheinlich nicht die eleganteste Antwort Sie erhalten, aber nur diese dort werfen:

Sie rein json aus dem Aktionsmethode zurückkehren konnten,

etwas, das würde wie folgt aussehen:

{ 
    Html: "<div class=\"person\"> etc...", 
    Json: { // your object here 
      } 
} 

in Ihrem Controller werden Sie so etwas wie dieses benötigen eine Ansicht zu machen:

var existingContext = HttpContext.Current; 
var writer = new StringWriter(); 
var response = new HttpResponse(writer); 
var httpContext = new HttpContext(existingContext.Request, response); 

var viewResult = myAction(bla); 

HttpContext.Current = httpContext; 

viewResult.ExecuteResult(this.ControllerContext) 

HttpContext.Current = existingContext; 
var viewAsHtml = writer.ToString(); 
+0

Interessant. Ich schaue mir das an, aber ich weiß nicht, ob das auch "richtig" ist, fast so, als würde man den MVC-Rahmen kurzschließen. Ich bin wahrscheinlich nur wählerisch :). – swilliams

+1

ich weiß, riecht ein bisschen hacky doesnt es? Warum gibst du deine Personendaten nicht einfach in den JSON zurück und erstellst den HTML-Code mit Javascript? –

+0

Es gibt einige Dinge in der Ansicht, die mit dem MVC-Templating viel einfacher zu machen sind. – swilliams

1

Die gleiche Lösung wie Andrew, aber vielleicht ein bisschen mehr MVC'ish ...

Erstellen Sie eine neue Klasse, die von ViewPage erbt. Überschreiben Sie die Render-Methode, um die Seite selbst zu rendern, und stopfen Sie sie dann in die von Andrew vorgeschlagene Ausgabe ein. Damit kommt das ganze Hacken in der Render-Methode vor, wo es passieren sollte.

Jetzt ansehen jeder, dass Sie erstellen Sie die Zeile:

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyModel>" %> 

mit

<%@ Page Title="" Language="C#" Inherits="CustomViewPage<MyModel>" %> 

Ich habe es nicht überprüfen selbst, aber denke, es sollte funktionieren. Wenn du willst, kann ich es versuchen und bauen.

0
public static string RenderPartialToString(string controlName, object viewData, object model, System.Web.Routing.RequestContext viewContext) 
      { 

       ViewDataDictionary vd = new ViewDataDictionary(viewData); 
       ViewPage vp = new ViewPage { ViewData = vd }; 

       vp.ViewData = vd; 
       vp.ViewData.Model = model; 
       vp.ViewContext = new ViewContext(); 
       vp.Url = new UrlHelper(viewContext); 

       Control control = vp.LoadControl(controlName); 

       vp.Controls.Add(control); 

       StringBuilder sb = new StringBuilder(); 

       using (StringWriter sw = new StringWriter(sb)) 
       { 

        using (HtmlTextWriter tw = new HtmlTextWriter(sw)) 
        { 

         vp.RenderControl(tw); 

        } 

       } 

       return sb.ToString(); 

      }