Your in luck, I've done this!
So the first thing you need is a new ViewEngine to handle rendering a page without all the normal header/footer stuff that will get in the way of your modal windows. The simpliest way to do that is to use a mostly empty master page for your modal windows. You want the master page switching logic out of the way and in a custom ViewEngine because otherwise each controller method is going to have to have if() else() all over the place detecting IsAjaxRequest(). I like dry, sahara dry.
With this technique I also have the advantage of degrading very gracefully. My site functions without javascript just perfectly. Links are fine, forms work, zero code changes to go from "modal aware site" to plain old html form submits.
All I did was subclass the default engine and add some MasterPage selection bits:
The View Engine:
public class ModalViewEngine : VirtualPathProviderViewEngine
{
public ModalViewEngine()
{
/* {0} = view name or master page name
* {1} = controller name */
MasterLocationFormats = new[] {
"~/Views/Shared/{0}.master"
};
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/Shared/{0}.aspx"
};
PartialViewLocationFormats = new[] {
"~/Views/{1}/{0}.ascx",
};
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
throw new NotImplementedException();
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new WebFormView(viewPath, masterPath );
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
//you might have to customize this bit
if (controllerContext.HttpContext.Request.IsAjaxRequest())
return base.FindView(controllerContext, viewName, "Modal", useCache);
return base.FindView(controllerContext, viewName, "Site", useCache);
}
protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
{
return base.FileExists(controllerContext, virtualPath);
}
}
So my Modal.Master page is very simple. All I have is a div wrapper so I know when something is rendered inside the modal window. This will be helpful when you need to select certain elements with jquery only when the elements are in "modal mode".
Modal.Master
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<div id="modalcontent"><asp:ContentPlaceHolder ID="MainContent" runat="server" /></div>
The next step is to create your form. I use the default property name = input name so I can model bind easily and keep things simple. Nothing special about the form. I looks just like you'd do it normally. ( Note I'm using MVC 2 and EditorFor() in my code but that shouldn't matter ) Here is my final HTML:
HTML Output
<div id="modalcontent">
<h2>EditFood</h2>
<div id="form">
<form method="post" action="/edit/food?Length=8">
<input id="CommonName" class="text-box single-line" type="text" value="" name="CommonName"/>
<input class="button" type="submit" value="Edit Food"/>
</form>
</div>
</div>
Besides model binding really nicely you can also use the Jquery.Form plugin to have seemless and easy ajax capabilities layered into your application with minimal code. Now I've chosen ColorBox as my modal window script purely because I wanted Facebookesque transparent corners and I like the extensibility points the author added.
Now with these scripts combined you get a really nice combination that makes this technique really stupid easy to do in javascript. The only javascript I had to add was ( inside document.ready ):
Javascript/Jquery
$("a.edit").colorbox({ maxWidth: "800px", opacity: 0.4, initialWidth: 50, initialHeight: 50 });
$().bind('cbox_complete', function () {
$("#form form").ajaxForm(function () { $.fn.colorbox.close() });
});
Here I'm telling ColorBox to open a modal window for my edit links ( Edit Food ). Then binding go the colorbox's complete event to wire up your ajaxform stuff with a success callback to tell ColorBox to close the modal window. Thats it.
This code was all done as a proof of concept and thats why the view engine is really lite and there is no validation or other standard form bling. ColorBox and JQuery.Form have tons of extensibility support so customizing this should be easy.
Note this was all done in MVC 2 but here is my controller code anyway just to show how easy this is to do. Remember my proof of concept goal was to get modal windows working in such a way that I didn't have to make any code changes other than set up some basic infrastructure.
[UrlRoute(Path="edit/food")]
public ActionResult EditFood()
{
return View(new Food());
}
[HttpPost][UrlRoute(Path = "edit/food")]
public ActionResult EditFood(Food food)
{
return View(food);
}