Since the new ASP.NET 3.5 MVC Framework preview is out (can we please call this thing MVC.NET??), and I've heard a lot of questions about AJAX in an MVC world, I decided I'd try the script.aculo.us client-side JavaScript + AJAX framework out for a try and see if I could get at least one of their fancy controls to work. I decided to start with the simplest example: The Ajax.Autocompleter (sic).
Download Script.aculo.us
First, I downloaded the 1.8.0 release of script.aculo.us from here: http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter
Create Project in Visual Studio
Next, I created a new ASP.NET MVC Web Application:
(Figure 1: New MVC Web Application project dialog)
Deploy Script Files
Next, I dropped all the script.aculo.us files into my Content folder, so it ended up look like this:
(Figure 2: script files in Content folder tree)
Reference Scripts On Page
I'm going to add a simple 'Search' textbox on the main "Index.aspx" page that gets added automatically by the ASP.NET MVC Web Application project. After the auto-generated "Welcome to my ASP.NET MVC Application", I put the following lines:
<script src="../../Content/prototype.js" type="text/javascript"></script>
<script src="../../Content/scriptaculous.js" type="text/javascript"></script>
Next, I added some HTML for the input box and some of the extra 'flare' that the Ajax.AutoCompleter adds (such as a 'Working...' indicator and the pop-up div in which the results will be displayed):
Search For Something Cool:<br />
<input type="text" id="autocomplete" name="autocomplete_parameter"/>
<span id="indicator1" style="display: none">
<img src="/images/spinner.gif" alt="Working..." />
</span>
<div id="autocomplete_choices" class="autocomplete"></div>
Next, add the JavaScript call to initialize scriptactulous' AutoCompleter to attach to the HTML and do it's thang:
<script type="text/javascript">
new Ajax.Autocompleter("autocomplete", "autocomplete_choices", "/Search/AutoComplete", {paramName: "searchValue", minChars: 2, indicator: 'indicator1'});
</script>
NOTE:
Notice the /Search/AutoComplete URL and the 'searchValue' paramName? Remember these, we'll get to them later. This is what connects the client side back to the server via AJAX.
Finally, it wouldn't be "Web 2.0" if it didn't look good. I'm going to use the sample CSS that the scriptaculous folks used in their documentation sample. So I crack open the /Content/Site.css file and paste these at the bottom:
div.autocomplete {
position:absolute;
width:250px;
background-color:white;
border:1px solid #888;
margin:0px;
padding:0px;
}
div.autocomplete ul {
list-style-type:none;
margin:0px;
padding:0px;
}
div.autocomplete ul li.selected { background-color: #ffb;}
div.autocomplete ul li {
list-style-type:none;
display:block;
margin:0;
padding:2px;
height:32px;
cursor:pointer;
}
Ok, all the client side stuff is done. What wasn't too painful, was it? Nothing earth-shattering here. Just some JavaScripts, some HTML, and some CSS. Next is where the interesting part comes in:
Add the Controller
Remember I mentioned that /Search/AutoComplete URL? Now we're going to make that a reality. What I did to get started was to copy the already-existing "HomeController" that Visual Studio generated for us and rename it to "SearchController" both at the file name and class level.
I then added a new action named 'AutoComplete' and gave it a real simple implementation which accomplishes the following task flow:
- Look for the 'searchValue' Request Form/POST variable (remember I said to remember both 'AutoComplete' and the 'searchValue' parameter? Well, here's where they both become important!)
- If searchValue is NOT present, render the AutoComplete view with an empty result set (nothing will happen on the client)
- If searchValue IS present, get a list of search terms from somewhere (database? file system? hard-coded? We'll use hard-coded for the demo because it's easier) and see if any terms STARTS WITH the searchValue.
To be as simplistic as possible, I used the following code (yes, I know it is missing a lot like validation, security, etc, but this is just for illustration):
[ControllerAction]
public void AutoComplete()
{
string searchValue = Request.Form["searchValue"];
IEnumerable<String> searchTerms = new string[0];
if (!String.IsNullOrEmpty(searchValue))
{
searchValue = searchValue.Trim().ToLowerInvariant();
searchTerms = GetSearchTermsFromSomewhere().Where(s => s.StartsWith(searchValue));
}
RenderView("AutoComplete", searchTerms);
}
Add the View
Now I need to add a view. Under the 'Views' folder, I add a new folder called 'Search' and I r-click on the 'Search' folder and add a new item. When the 'Add New Item' dialog pops up, I select 'ASP.NET MVC View Page' and call it 'AutoComplete.aspx". My project looks something like this now:
I'd like to use the foreach command in C# in order to iterate over the search terms for presentation to the client. In order to do this, I need to let ASP.NET MVC know that I need ViewData which implements IEnumerable<string> so that I can use foreach.
I go into the codebehind and change:
public partial class AutoComplete : ViewPage
to this:
public partial class AutoComplete : ViewPage<IEnumerable<string>>
Write the View
Finally, The AutoCompleter client script expects the view to return a simple, unordered HTML list using the <ul><li></li></ul> syntax. That's it. Just a partial HTML document (no <html> tag, etc). So the first thing I do with the AutoComplete.aspx HTML is clear out everything but the <%@ Page directive. I then add a simple script to dump the <ul> with the returned search terms. This is what I ended up with in the ASPX file:
<%@ Page Language="C#" ...
<ul>
<% foreach (var searchTerm in ViewData) { %>
<li><%= searchTerm %></li>
<% } %>
</ul>
Run it!
That's it. We compile and then run it (F5) and see what happens. I see the search textbox, and then I start typing, and I get this:
Conclusion
This post is rather longer than I had hoped, but the steps are super easy to follow. In fact, it seemed that getting the script files out of the ZIP file and onto my file system was the most complicated part, hah!
In the next few weeks I'm going to be going through and mining script.aculo.us and figuring out how easy or difficult it will be to adapt those controls and AJAX methods to the ASP.NET MVC framework preview, so please stay tuned.
Also, if you've done anything similar to this, let me know and I'd like to start building up a list of links for doing AJAX-y type stuff with the ASP.NET MVC framework.