One of the coolest features of ASP.NET MVC is seeing html again and being able to manipulate it in ways that the php folks have been doing for years.
I have been guilty of forgetting that javascript and html are the key components to an ajax call and been using ajax.net instead of digging into the heart of the XMLHttpRequest Object. Fortunately a number of javascript libraries that help ease the creation of a real javascript ajax call. For this example I will be using jquery, though it is important to note that this same technique will work with any of the other javascript helper libraries available that include ajax capabilities. If you feel especially hands-on you can try this sample with the classic javascript code.
For this example you will need jquery, JSON.NET, and ASP.NET MVC Preview 3
Step 1 : HTML
<html>
<head>
<title>Sitemap Manager</title>
<script src="../../Scripts/jquery-1.2.3.js" type="text/javascript"></script>
<script type="text/javascript" src="../../Scripts/EditTree.js"></script>
</head>
<div id="tree">
<ul id='browser' class='filetree'>
<li id='2'><span class="folder" onclick='javascript:getNodeDetails(2)'>Home</span></li>
<li id='3'><span class="folder" onclick='javascript:getNodeDetails(3)'>Recordings</span></li>
<li id='4'><span class="folder" onclick='javascript:getNodeDetails(4)'>Store Locations</span></li><ul>
</div>
<form id="NodeDetailsForm" action="SaveNode" method="post">
<fieldset>
<legend>Menu Link Details</legend>
<input type="hidden" name="hfSitemapId" id="hfSitemapId" />
<label for="txtMenuName">
MenuName</label>
<input type="text" name="txtMenuName" id="txtMenuName" />
<br />
<label for="txtHref">
LinkHref</label>
<input type="text" name="txtHref" id="txtHref" />
<br />
<input type="submit" value="submit" id="submit-button" name="submit-button" />
</fieldset>
</form>
</html>
The form tag could also be replaced with: <%=using(Html.Form("Sitemap", "SaveNode")){ %>
Step 2 : Javascript
I wanted to keep this first example as simple as possible to illustrate how easy it is to use jquery ajax instead of ajax.net. The $ operator is the heart of the jquery library, for a better explanation head over to the site and investigate, as there are numerous other articles written about this library. For this example I am going to refrain from using the $ operator everywhere because I don't want to intimidate the newcommers.
function getNodeDetails(id)
{
$.getJSON("NodeClicked?id="+id,
function(result){
document.getElementById('hfMenuID').value = result.MenuID;
document.getElementById("txtMenuName").value = result.MenuName;
document.getElementById('txtHref').value = result.LinkName;
});
}
getNodeDetails(id) calls $.getJSON will send a HttpGet command to the url specified. The controller class in asp.net mvc will attempt to find an action to match the url ("NodeClicked").
Once the result is recieved from the url the function(result) portion will be run, filling the html elements with appropriate values is fairly straight forward from here. Notice how clean and friendly javascript looks using json, it's identical to the C# code...
Step 3 : The Controller
public ActionResult NodeClicked()
{
string id = this.ReadFromRequest("id");
MerriweatherDataContext db = new MerriweatherDataContext();
var node = (from s in db.MenuLayouts
where s.MenuID == Convert.ToInt32(id)
select new { s.MenuName, s.LinkName }).First();
string json = JavaScriptConvert.SerializeObject(node);
Response.Write(json);
return null;
}
First I grab the "id" parameter from the querystring and return a custom select statement. I tried this example without the custom select statement and ended up with a "self referencing loop" error, so I strongly advice considering what data you need and returning only the relevant fields.
Next I use JSON.NET to serialize the the node object into a json string.
Instead of using RenderView(), I use Response.Write which allows the javascript function to interpret the json result.
I'm using MVC Preview 3 and as a result the controller action requires something to be returned, so I return null. If anyone knows of a more elegant solution I would love to hear the solution.
Finally the code I am sharing is part of a larger cms project that I am working on and hope to release as an open source project eventually...but really don't we have enough custom cms solutions out there already?
*Before anyone flames me the DataContext object should not be called from the controller but for the purpose of this example I'm ignoring that piece of logic.
