Use case and goals
Often times in building a web application we have the need to store some type of user configuration for the lifecycle of a user's visit on the site. Typically we turn to the Session to store this data and we accomplish that by posting some type of form data to a server side script and then reloading the page.
With ASP.NET MVC 3 it is easy to write up controller actions that work with JSON data and add some jQuery code in views to interface with those actions via Ajax. We can use that approach to capture and post user settings to some server side code and return the user's settings back without having to reload a page or redirect the user.
We will be creating a prototype application that will have a list page that displays a list of data records consisting of a name and a description. It will allow the user to set the list view to either rows or a grid of blocks. There will also be an option to show or hide the description. When the user sets their desired options we will store them in the Session state. Finally, we want to update the view without reloading the page.
Scaffolding for read/write with the Session
We begin by creating a class for our settings structure that we will use with model binding to store and work with our JSON data from our view. This allows us to use one key/value pair in our Session state instead of storing a key/value for each of our settings. It also provides us with additional control over our data content, thus we can craft some code to protect ourselves from potential cross site scripting vulnerabilities since we will be receiving post data into our action method. Our class will be named ListSettings and will contain two properties named ListView and ShowDescription.
Listing 1: ListSettings.cs
With our settings class defined we can build out our SettingsController class. This class will contain an action method named Save that will take in a ListSetting object, save it in the Session state, and return the object (we will learn why when we get into the jQuery code later in the article). We will also create an action method named Load that will instantiate a default ListSettings object, get the data in the session (if any) and return it as a JSON object.
Listing 2: SettingsController.cs
Controllers and views for the UX
Next we need to set up our user experience layer. We will add a home page and a list page so we can navigate between the two and test our session state. The HomeController will contain the action methods Index and List. Since we want to handle all of our UX updates via Ajax we do not need to add any logic in here to load up the settings for our display.
Listing 3: HomeController.cs
The Index.cshtml view file contains a heading tag to let us know where we are at.
Listing 4: Index.cshtml
The List.cshtml view file will contain the buttons to set the list view type, a button to toggle the description option and an unordered list of our sample data. We will decorate the unordered list with a CSS class named Hidden that will hide the display of the list until we can determine the user settings via some jQuery. The buttons and the unordered lists will get id attributes so we can target them within our jQuery. The data in the list items will also get CSS classes for some styling and to handle the toggle of the description. The html markup portion of the List.cshtml file looks like:
Before we craft the jQuery code let's build out the CSS that we need. We can add the following CSS to the existing Site.css file that is in the default MVC 3 project.
The Button class styles our span tags to make them look interactive. The Hidden class sets the display to none. We use this class for the unordered list as well as the description elements. Using the
ItemListing id, we set a fixed width on the unordered list so our grid layout will be a set number of blocks wide (in this case it will be 3). We also normalize the styling on the unordered list by setting the list type to none and the margin/padding to zero. This will remove the disc glyph and left indention so we can have our list looking like rows or columns of blocks. The Name and Description classes add some styling to our text. Finally, the Rows and Grid classes set the style of the
li elements to control the way the list items are viewed. The Rows sets the width of each
li to the same width as the unordered list. The Grid sets the width on each one smaller, floats them to the left and adds some margin to the right and bottom of each so they don't run into each other. The width of the unordered list will force the grid blocks to wrap, thus achieving the 3 column look.
The jQuery code in the List.cshtml file will handle the user interaction with the settings buttons and updates to the list view. We begin by defining a settings variable that will be global so our functions can access the data in it. Then we will add the jQuery on document load block to wire up our button clicks and add a call to a function called LoadSettings. The final part of script will be our functions to save and load the settings, a callback function to handle the settings loaded event, and a function to set the list view.
The code for setting the list view type handles setting the
SaveSettings method. The
SaveSettings method posts the settings object to our
Save action method in the SettingsController and upon success receives the returned JSON object from that action method and calls the
SetListView function. The code to toggle the description visibility sets the
ShowDescription property to the opposite of what it currently is (in effect, toggling its state) and then makes the call to
SetListView function makes the view changes to the ItemListing by removing the Hidden class and each of the possible list view classes and then adds the selected list view class (we are using the name of the list type as the name of the CSS class). It also checks the
ShowDescription property and either removes or adds the Hidden class on the elements with the Description class.
LoadSettings function makes a post call to the Load action method in the SettingsController and upon success calls the
OnSettingsLoaded function. The
OnSettingsLoaded function sets the returned JSON object to our settings global variable and then calls the SetListView function. The reason we need to set the global settings object here is so the event handler for the toggle description button has access to the current settings for the
That's all that is needed for our view. The end result for our List.cshtml file:
Listing 5: List.cshtml
The last piece we will add is some navigation in our Layout.cshtml file so we have a way to switch back and forth between the home and list pages.
Listing 6: _Layout.cshtml
Now we can run our application, change up our view settings, and navigate back and forth between the home and list pages to see that our settings are remaining in their proper state.
Adapting to changes in requirements
Listing 7: SettingsController.cs
With this approach we are able to store and retrieve data on the fly from our application interface and can respond to the user's request for change with an instant update rather than a page reload. Enhancements to the user experience accomplished with relative ease using MVC and jQuery.
I have been entrenched in web application development for quite a while and have traversed the syntactic jungles of PHP, classic ASP, Visual Basic, VB.NET, and ASP.NET Web Forms. However, I have found a guilty pleasure in ASP.NET MVC since its beta launch and have since refactored my web stack focus...
This author has published 3 articles on DotNetSlackers. View other articles or the complete profile here.
You might also be interested in the following related blog posts
Updated SilverTwit Code for MSDN Magazine
How do ASP.NET Application_ Events Work
CodeDigest.Com Article,Codes,FAQs - April,2009
Using NHibernate with multiple databases
What is .NET RIA Services?
Convert Web.UI Grid into a data entry spreadsheet
Sir DevFishs Crusade of Enlightenment
Session Slides and Samples from Microsoft ASP.NET Connections
Running the Same Query Against Multiple Databases
Please login to rate or to leave a comment.