Real world Knockout JS example

In my recent exploits I put KnockOut JS (KO) through a real worldy example. I tried to assemble everything I believe an enterprise app is going to need, to get started. The app is a trade entry screen which allows the user to enter a trade and shows updates in a grid/blotter. As rows are clicked they show up on the event viewer as events.

Screen shot of the sample app

Web client stack

Single Page App (SPA) which communicates to the server exclusively via a REST API.

  1. Knockout JS
  2. Curl JS as the AMD loader. Provides client side Dependency Injection too.
  3. Postal JS for intra app communication
  4. Knockout-amd-helpers plugin – to load KO templates and componentize the UI
  5. jQuery UI for the date widget. Bound using Knockout-jQueryUI bindings
  6. Kendo UI for the Grid widget. Bound using Knockout-KendoUI bindings
  7. Atmosphere-jQuery for consuming updates over web sockets with fallback
  8. Log4javascript for logging. Provides REST based async logger too.
  9. Jasmine for unit tests. Integrated with Curl.

Server side stack

  1. Jetty
  2. Spring MVC. Jackson for JSON serialization.
  3. Atmosphere library for data pushes
  4. Maven
  5. Selenium for acceptance tests. Selenide to make life easier.
  6. JRebel for auto reloading Java code.

How to run the sample

You will need to have Maven installed. Everything else will be pulled down.

git clone https://github.com/bsandhu/myserver.git
mvn jetty:run

Once the server starts, navigate to http://localhost:8080/myserver/resources/js/app/views/App.html#

Web client code walkthrough

Screen Shot 2013-06-04 at 3.23.37 PM The code is available on Github in all its glory.

Basic setup

Since this is a Java based app, the directory layout follows Maven. Maven support for JS is a bit all over the place. I should probably follow the JS layout specified by this mojo.

Screen Shot 2013-06-04 at 2.21.40 PM

The client is bootstrapped by Curl. Curl is a JS module (lib) loader which can asynchronously load JS in the browser. Additionally it loads them in the order of dependencies. Once these dependencies are declared they can be referenced by the key name throughout the app. Makes it easy to upgrade and inject the JS libs. Here is the curl config. I tried using RequireJS too but found Curl to be easier and more intuitive.

Screen Shot 2013-06-04 at 2.37.38 PM

App.html is the entry point to the application.

  • This is where all the KO templates and View Models are bound. Each template has a backing VM and represents a self contained UI component. Note that the View Models (VM) are loaded via the knockout-amd-plugin.
  • The Kendo splitter component is bound to KO using the KO-kendo binding lib.

AppView

Nested components

In EventsView.html you can see nested UI components/templates (UpdatesView). Each UI component is unaware of any other components. It publishes its own state changes and listens for events from the outside world – via Postal JS, a client side messaging solution. The following snippet EventsViewModel.js is:

  • Defined as an AMD component (define fn) so it can be managed by Curl.
  • Bound to the tabular view (top right in the screenshot above)
  • Listens for selection events on the trade blotter channel. (In Postal JS you can listen selectively to channels, so it doesn’t have to broadcast each message to each listener)
  • Stores the msg in HTML 5 local storage usage.

EventsVM

Factoring out common services

It helps to separate common services into their own modules and inject these into the VMs as needed. This promotes modularity and testability. This is shown in the TicketViewModel.js where TradeService is injected. The TradeService module can potentially be stubbed out for testing (Spies in Jsamine).

Trade VM2

Testing the View Models

I plan to cover View Models/services with Jasmine based unit tests. There is a little bump in the road – Jasmine now needs a reference to a VM which is usually put together by Curl. Hence, Curl needs to do the same for the test context. I had to modify the Jasmine spec runner a little bit to achieve this. This solution requires you to specify the Spec under test as a dependency. This could be improved.

Screen Shot 2013-06-04 at 3.14.57 PM

Screen Shot 2013-06-04 at 3.15.19 PM

Up Next

In the next post I will walkthroug the Atmosphere implementation on the client and the server and its integration with Spring MVC.

Advertisements
This entry was posted in Tech bits, Web development and tagged , , . Bookmark the permalink.

One Response to Real world Knockout JS example

  1. I liked your post. I’ve been struggling to tame Knockout and your review of Curl was really helpful to me.

    What has your experience been with Knockout and memory leaks? After some fairly heavy usage with a single page app I found that I was consuming a fair bit of memory and had orphaned DOM elements despite my cleaning up of subscriptions. My solution was to break my page down into several view models in the hope that garbage collection could occur sooner. Given how extensive your solution is I wondered what you have experienced in the past.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s