Code Highlighting

Tuesday, September 4, 2012

About those animated ajax page loads in MVC ...

A little while ago I showed a way to chain animation functions with callbacks in javascript. That was part of a web site in MVC the requirements of which were as follows:

  • It needs to use awesometastic animation prettiful swooping panel dynamified load superlicious "Html5" etc.
  • It needs to do well in search engines, and
  • work reasonably well in IE7
The animations were part of the ajax-loading of the page content, but -of course- people needed to be able to link to any page directly as well.

So here's what I did:

  • I created a ViewConfig class. This class contains the current configuration of the browser screen: what menus are shown, which background(s) are showing, etc etc:
        public class ViewConfig
        {
            [JsonConverter(typeof(StringEnumConverter))]
            public MenuDisplay Menu
            {
                get { return _showMenu; }
                set { _showMenu = value; }
            }
    
            [JsonConverter(typeof(StringEnumConverter))]
            public BackgroundsDisplay Backgrounds
            {
                get { return _backgrounds; }
                set { _backgrounds = value; }
            }
    
            public string Root
            {
                get { return _root; }
                set { _root = value; }
            }
    ...
    
  • I created a BaseModel class that includes a ViewConfig property (and my menu data and other data shared among all models):
        public abstract class BaseModel
        {
            public List<Business.MenuItem> MainMenuItems
            {
                get { return _mainMenuItems; }
                set { _mainMenuItems = value; }
            }
    
            public ViewConfig ViewConfig
            {
                get { return _viewConfig; }
                set { _viewConfig = value; }
            }
    
            [JsonIgnore]
            public string ViewConfigJson
            {
                get { return  _viewConfigJson; }
                set { _viewConfigJson = value; }
            }
    ...
    
  • Each controller takes a boolean json parameter that determines if the Model will be sent to the view, or rather simply returned as a JsonActionResult:
        public class InhoudController : BaseController
        {
            public ActionResult Index(string taal, string inhoudId, string json)
            {
                bool returnJson = "true".Equals(json);
                Models.InhoudModel model = new Tabeoka.Epsilon.Web.Models.InhoudModel();
    
    ...
    
                if (returnJson)
                {
                    var jsonResult = new JsonNetResult();
    
                    jsonResult.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                    jsonResult.SerializerSettings.MaxDepth = 1;
                    jsonResult.Data = model;
    
                    Response.Expires = 0;
                    Response.CacheControl = "no-cache";
    
                    return jsonResult;
                }
                else
                {
                    model.ViewConfigJson = model.ViewConfig.ToJson();
                    return View(model);
                }
    
  • In the pages I then simply send an ajax request, get my model as json, and move, step by step, from my current ViewConfig to the new ViewConfig, using supertastic fantalicious animations.
There are just two obvious drawbacks to this approach:

  1. As you can see, I need to send my ViewConfig twice; once as a string for the initial ViewConfig when a page is loaded through a View. The second when the entire model is serialized to json. It's ugly. I could serialize in my View to fix this.
  2. Worse: I have a bunch of html rendering code in javascript. Ideally I would be able to use the same template in javascript and .Net. I'm not sure how and if that could work though.
Search engines and javascriptless (or javascript-poor) clients, I can just present a static version of the site. Other browsers will automatically have links on the page 'ajaxified'.

Conceivably in the future I can take this approach, and improve it by POSTing my current ViewConfig in my ajax request, build the exact delta between that and the requested page, and only fill up my Model with data to the extent my ajax code needs it.

Menno

No comments:

Post a Comment