Wednesday, May 7, 2008

Simple ASP.NET MVC jquery ajax call

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.

Friday, May 2, 2008

Jesse Naiman - Introduction

Before I get started I want to send a thank you out to Rob Conery, Scott Gu, Phil Haack, Scott Hanselman, and all the other amazing bloggers out there for helping me reach a point where I feel that I can contribute to the community.

This is my first technical blog so please be forgiving, as I'm bound to publish a few errors. I'm going to try to write articles that fill in the blanks in some of the larger topics that have recently emerged.

There's a lot of great information already out on the web, so I'm going to try not to repeat anything that has already been said. My current focus is on asp.net mvc, unit testing, mocking frameworks, svn, jquery, subsonic, linq and anything else that happens to catch my eye.

This blog and myself cater to the perpetual beginner who understand that knowledge has no definitive end.

Subsonic Integration with Visual Studio

Getting SubCommander to work properly in visual studio is a little tricky. Luckily Rob Conery's excellent video showed me how to add a button that generated the classes.



Working like mad to complete deadlines doesn't give me much time to find time or justify watching a video at work. As a result of doing a presentation at work on SubSonic I created these handy steps to configure SubCommander within Visual Studio.



SubCommander Visual Studio Configuration
1) Click Tools -> External Tools --> Add




3) Name the tool SubSonic DAL (Or Anything you want, I like consistency myself and the online demo uses this name)


4) In the command field locate the sonic.exe, which is by default installed at: "C:\Program Files\SubSonic\SubSonic 2.0.3\SubCommander\sonic.exe"


5) In the arguments field put this: "generate /out [generated]". The value in the bracket is the directory that the generated files will be placed. It actually looks like this: "generate /out generated"


6) For "Initial directory" put "$(ProjectDir)"


7) Check "Use Output window" and "Prompt for arguments" It should look similar to the image below:



8) Save. This button is now in the Tools menu. Note the placement of this menu item for step 4.


9) Right click on the toolbar --> Click Customize --> Click "Toolbars" tab --> Click New --> Name the toolbar item "SubSonic" (It can be anything you like)4) Click "Commands" tab-> Scroll to Tools in the left hand menu-->Navigate to the external Command# that corresponds to the placement of the SubSonic menu item and drag to the toolbar.


10) You're ready to go. Whenever the schema changes run the SubSonicDAL button and the files should be ready to go.