Loading KnockoutJS View Models from ASP.Net MVC, for faster page loads

This is a little deep dive that came out of a previous post on my SignalR Series.

 

Background

First lets talk about a little background.  The popularity of the Single Page Application (SPA) has seen its rise and fall, as companies like twitter moved from server side page renering to loading the initial page with ajax calls back to the server. Then after a few months, they moved back to initial server side rendering because of the perceived page load to the browser. After all, the aspect of user experience that matters on the web is perceived page load.

The Problem

Now, lets fast forward. While we can deliver a faster initial page load using server side rendering, if we want to update the web page after it has loaded with data from an ajax call we get into a dilemma of having both server side templates and client side templates to maintain.  This is the part that sucks from a code maintainability aspect. This means extra work when you add a new feature or fix a bug. Even worse, you may fix a bug in on and not realize it needed to be fixed in the other template technology.

A Solution

The solution using ASP.Net MVC and KnockoutJS is pretty simple. Rather then loading the viewmodel from an ajax call just write the viewmodel from the server side razor template as a JSON object into the javascript of the page. Then use the KnockoutJS Mapping plugin to map from the json object to the observable objects required by KnockoutJS. To install the mapping plugin, use the nuget package.

There are two pieces of code needed to make this solution work.


Access the mapping plugin by calling ko.mapping in the view and pass in the JSON representation of your server side view model.  That brings us to the .ToJson extension method. This is a small piece of code I wrote to simplify the Json serialization using Json.Net.

This little trick will simplify your code maintenance and also clean up your client side view models, by reducing the amount of object initialization you need to write. This really comes into play when you have a number of collections on your viewmodel.

Follow me on RSS and Twitter

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Eric Hexter

I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
This entry was posted in Asp.Net, Asp.Net MVC, CodeProject, javascript, knockoutJs. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://twitter.com/damnmaxims damnmaxims

    Wait!! Single Page Applications have already fallen! And I just watched John Papa’s SPA tutorial on Pluralsight :( . I don’t understand you first paragraph exactly. Did Twitter revert back to server side rendering because the initial SPA page load took too long?

    • Dave Van den Eynde

      Yes, more specifically because they felt that loading HTML is faster than rendering it with JavaScript, as outlined here: http://www.webmonkey.com/2012/05/twitter-declares-everything-old-new-again/

      Then again, they’re pretty big on having the ultimate speed on page loads, and they have a lot of resources to maintain such a hybrid solution. I think the solution outlined in this article is a good tip, but it makes for poor client side caching. 

      • http://twitter.com/damnmaxims damnmaxims

        Nice! Thanks for the feedback. I try not use new technology just because it is new and cool. But John Papa’s SPA tutorial on Pluralsight got me stoked to design a web application in a similar fashion. So many seemingly awesome ways to do things! I am making a new real estate app that I felt would really benefit that “desktop” app feel that a SPA can bring. Maybe I will just do more of a MVC4. Decisions decisions. Hey do a write up on NoSQL if you have any thoughts. I have checked out MongoDB and RavenDB. RavenDB is pretty sweet so far.

  • Rémi BOURGAREL

    I wrote this little extension method :

    public static MvcHtmlString GetAsKnockoutModel(this HtmlHelper helper, object model) { var initialData = helper.Raw(JsonConvert.SerializeObject(model, new IsoDateTimeConverter())); return new MvcHtmlString(“ko.mapping.fromJS(“+initialData+”);”); }

  • http://ajondeck.net aherrick

    Looks good but why isn’t the mapping plugin built into Knockout? This is “prefetching” right? This is a double win. You don’t have that additional server hit on page load (to retrieve the data) and I don’t have to re-define properties in the JS?

  • http://twitter.com/ctrlshiftbryan ctrlshiftbryan

    Have you figured out how to do this if your json is coming from a WebAPI controller?

    • erichexter

      That is a different thing all together.. Since a webpi controller does not render html, it does not make sense. This post is about optimizing the first page load. What could make sense is use this approach to render the first page, then use webapi to update the knockout model, or even signalR.
      Eric Hexter

      blog | http://Hex.LosTechies.com
      info | http://www.linkedin.com/in/erichexter

    • erichexter

      Your right on.. it is pre fetching.. I don’t know why the mapping plugin is not built in.. It seems like a no brainer to me to include it.

      • http://www.marastat.com runxc1

        Having used the mapping plugin on a few pages with large amounts of data I am not a big fan of the mapping plugin as it tries to do a comparison of objects being added and update the properties so it seems to slow down at an exponential rate as the amount of objects being added grows.  Their is a knockout.wrap plugin with almost an identical api that performs much better with larger amounts of data that you are binding to.

        • erichexter

          Good to know. What size of object caused issues with the plugin?

          • http://www.marastat.com runxc1

            It was an array with a couple hundred items in it where I first noticed the problem.  Most everything I have moved to ko.wrap and noticed a speed improvement with some small arrays of 50 or so.

          • erichexter

            good to know. thanks for the update

            Eric Hexter

            blog | http://Hex.LosTechies.com
            info | http://www.linkedin.com/in/erichexter

  • http://www.joshka.net/ Joshua McKinney

    My colleague, Aaron Powell covered a similar method for this, and highlights a few extra concerns. http://aaron-powell.com/javascript/creating-vms-from-server

  • http://www.facebook.com/trevor.germain Trevor Germain

    Be careful about how large your model is if you need to support IE7 or IE8. Mapping a large data set from your model to knockout, then binding it to templates can cause the dreaded “A script on your page is taking too long” dialog.

    Also, don’t forget that browsers are disconnected from the server. If you load a large dataset into the browser to edit as a single page application, you run the risk of losing all of your edits if the session expires or a connection issue occurs.

    I love KnockoutJS, btw… but have learned through some good and bad experiences that it is a good tool to supplement your application (UI behaviors, update elements based on model state, etc.), but maybe not the catch all for data binding. That’s what Mvc’s Html helpers are for!

  • Nick Olson

    Great technique but I’ve got a post about some drawbacks as well..
    http://codewith.us/drawbacks-of-using-knockout-mapping/

    • Eric Hexter

      great post.. I will link back to it.

  • http://twitter.com/andleer Andrew Robinson

    Eric, I am very new to ko and the world of client side development so I ask this from a learning prospective. Not trying to nitpick…

    Shouldn’t the StringWriter be wrapped in a using block?

    Second, and the meat of my question, does this approach really improve performance? By embedding your data, your view is no longer static. Does an async JavaScript call and a static view perform better than a larger dynamic view? And doesn’t this move us away from the ideal MVVM pattern and one of the main reasons for using ko? If you simply want a templating engine, would you be better off using something like jsRender (which I have never used)?

    Thanks for any feedback….

  • Mikalai Silivonik

    In this article I see a disconnection between the problem you describes and the solution:

    The problem: using SPA we need to maintain server-side and client-side templates at the same time.

    The solution: don’t do initial AJAX call to load a view model, but render one with a page.

    • erichexter

      The problem injecting viewmodel as main solves is the time to load the install screen. It eliminates the need to make a blocking Ajax call to load the initial remodel. Another solution to this is to create a server side template..which is undesirable because of the additional maintenance.

  • Witiokz

    not practical …

  • Jason Sebring
  • Kun Yan

    Hi Eric,

    Great post!
    One thing need to be carefully is the special chars in JSON string. They need to be escaped. 

    • erichexter

      Using what escape format?

  • Rodd

    Eric, I’m just getting into a project in which I’m trying to mix MVC 4 with Knockoutjs.  The problem I’m having is that I wanted to load a single page with a list of objects.  When the user clicks edit on one of the objects, I want to open a modal dialog (jqueryui) and use AJAX to load a PartialView for the edit form in the dialog.

    My problem is with the submit.  If there are validation errors, I need to return the partial view again with the validation results.  However, if there are no errors, I need to return the JSON object … or at least the Id of the object (on an add).

    It seems kind of odd on the client side to have the AJAX call looking for html or JSON.  How have you handled this?

  • http://coloradobeach.yolasite.com/ FritzHester

    Excellent post. I want to thank you for this informative read, I really appreciate sharing this great post. Keep up your work.

  • Martin

    What about if you needed to write custom computed methods on your viewmodel? could you just “add” these after?

    Such as:

    viewModel.blah = ko.computed(function() { return true; });

    • erichexter

      I think it would work like that.. but you could try it out and post back here.

    • Jason Mitchell

      Yes

  • xelibrion

    I would rather put serialised model into data- attribute as it would not require javascript code to be in the view.

  • Arcan

    You can directly encode to json without writing the extension to json 
    var viewModel=ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
    i use this and it works

  • http://winmain.vn/gioi-thieu-phan-mem-vtiger-crm.html Phan Mem CRM

    Thank you for sharing superb informations. Your web-site is very cool. I am impressed by the details that you¡¦ve on this post. 
    Nice code

  • Elliot

    Thankyou.

  • Bhuvin

    Hey Eric , 
    I am doing the same thing , but not able to figure out if i need to append the data to the existing ones then how should i go about it ? 

  • http://www.facebook.com/1mandeep Mandeep Janjua

    I like your design idea. In fact we are following the same pattern to serve data over to views from db. There are few things that I think can be simplified more. I will list them below one by one -

    1. It is Json so do we really need to call Html.Raw?

    var viewModel = ko.mapping.fromJS(@Html.Raw(Model.ToJson()));

    2.  We do not need server side ToJson extension. Just make the following call right before passing in your data from UI to server side
       ko.toJSON(params) // or your viewModel

    asp.net mvc 3 has json model binder which will parse the received json into object of type that your are expecting in the controller action method.

    3. The results can depends on few factors but I think if you are not trying to load the whole universe then the total time taken to load the data + UI should be “almost” same whether you are  injecting viewmodel as part of first call or making a blocking Ajax call to load the initial data.

    Both the server side and client side templates are not required as long as you are using knockout to do the data bindings. It does not really matter how you are getting the data (initial call or blocking call) as at the end it is the knockout to push the data over to UI.

  • http://twitter.com/Nick_Johnsn Nick Johnson

    Model View Controller, an important and essential tool of asp.net development .

  • mu.weezlabs

    I’m also facing a slow loading time of my website http://weezlabs.com , and hoping it will work fine for me. Thanks!