I am building a asp.net webforms (3.5 sp1) application, using jquery where I can to animate the UI, change its state. It has worked great until I started doing postbacks, where the UI obviously resets itself to its initial state.
So my question is, what are the best practices for saving and restoring jquery/UI state between postbacks?
Thanks, Egil.
Update: Thanks a lot guys, great input, to bad I cant mark more than one answer as the "answer".
I typically store things like menu state or filter (set of inputs in a div) visibility, etc. server-side in the session via AJAX. When a menu expands or a filter is shown, the click handler will fire an AJAX event to a web service that will record the state of the menu or filter visibility in the user's session. On a postback I use the session variables corresponding to each menu/filter to set it's initial state via CSS. I find that this is better user experience since the page doesn't flash when it is updated by javascript after loading if you make the changes client-side.
Example -- as I'm on the road this not actual code from a project and may be incomplete. Uses jQuery. The Url for the web service is going to depend on how you implement web services. I'm using ASP.NET MVC (mostly) so mine would be a controller action.
<script type='text/javascript'>
$(document).ready( function() {
$('#searchFilter').click( function() {
var filter = $(this);
var filterName = filter.attr('id');
var nowVisible = filter.css('display') === 'none';
if (nowVisible) {
filter.show();
}
else {
filter.hide();
}
$.post('/controller/SetFilterVisibility',
{ name: filterName, visibility: nowVisible } );
});
});
</script>
<div id='searchFilter' <%= ViewData["searchFilterVisibility"] %> >
...
</div>
Server-side code
[AcceptVerbs( HttpVerbs.POST )]
[Authorization]
public ActionResult SetFilterVisibility( string name, bool visible )
{
Session[name] = visible;
return Content( string.Empty ); // not used...
}
[AcceptVerbs( HttpVerbs.GET )]
[Authorization]
public ActionResult SomeAction( int id )
{
...
ViewData["searchFilterVisibility"] = Session["searchFilter"];
...
return View();
}
I think you are referring to saving the state of the ui widgets between postbacks (rather than saving user preferences).
A lot of that state is applicable only to a particular widget, for a particular user, after a particular series of interactions (eg expand this tree node, click on that grid row, etc). This stuff doesn't have to go into the database, or even in the session, unless restoring state across page loads is important to you.
All that stuff I tend to put into an object or two, eg:
treeState.expandedNodeId = 'foo';
gridState.selectedRowIndex = 3;
Then I save it in a hidden field periodically:
$('.treeState').val(Sys.Serialization.JavaScriptSerializer.serialize(treeState));
etc.
The value is sent back with the postback result, and I just deserialize
it and restore my widgets from the saved values. Annoying, but it works well.
You have two options:
- Client side cookie
- Store UI settings server side via postback or webmethod calls
The second option will require alot more effort but would allow you to provide 'portable' UI settings that could be applied for a user regardless of client machine. If the settings are 'throw-away', I would go for client side cookies.
How to work with javascript and cookies:
http://techpatterns.com/downloads/javascript_cookies.php
I generally store UI settings server side in a database via postbacks, however if users are changing their UI via jQuery and you want to persist those changes, I would probably go about it something like this:
- add a script manager to your aspx page
- set EnablePageMethods="true"
- create a WebMethod in your codebehind
- in your jQuery methods that update the UI, add a call to your WebMethod and pass back the UI setting
- store any settings passed to the WebMethod in the database
- then when the user visits the page the next time, either fetch the settings and populate as many controls server side as you can, or use the jQuery ready method to make a call to another webmethod that fetches the UI settings from the database, passes them back to jQuery allowing you to populate the controls.
Here is a decent article on jQuery and WebMethod calls:
http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/
The problem you will need to be aware of is EventValidation; you will get into trouble if you fetch control values outside of the scope of the page lifecycle and then expect to use those settings on postback. For example, adding values to a dropdownlist via a webmethod will throw an error on postback, unless those values were also added to the dropdownlist when the page was built.
I'm using HTML5 storage, you can choose how to persist (local storage or per browser session). If you're worried about non HTML5 you can use Amplify.Storage. The downside is that you have to write the code to call the save/read. I'm looking at a way to automate this, if anyone has any ideas then please say. Thanks.