Custom events in WinJS

In this post, we’ll perform a refactoring that moves some code that controls the AppBar in a Metro application written in HTML5. The code is currently placed in each page in the application and each page searches the DOM for an element with an id ‘appbar’ and then hides or shows a button in the AppBar, depending on if a “full view” button should be visible or not. But even if we have data in the DOM available as global state, it doesn’t mean that we should use it – writing Metro applications in WinJS doesn’t change the fact that encapsulation is still an important property of the design of your application!

Image source: http://www.flickr.com/photos/124330160/2127121118/

First, the code to the finished example is found here: https://github.com/gustafnk/FeedReaderTechDays2012. Some of the old code is still commented out, in order for you to see what changes were made. (Next time I’ll create the git repo much earlier, tracking the changes made.)

In our example, we have a page, default.html, which creates a div which is an AppBar control, so it should also be responsible for turning on and off a button in the bar. But this is not the current case, instead all the other JavaScript files controls the AppBar, in the following style:

My goal with this example is to try to take as small steps as possible in the beginning of the refactoring and then, when I get confidence, try to take bigger steps.We first do a little research and see that itemsPage.js and detailsPage.js contains the code above that hides the app bar button named “Full view”. The file splitPage.js is the only place which shows the button.

Feedback through the console

First, let’s test if we can receive an event and act on it. An event is something that has happened, so we use “past tense” for the name. Also, the name of the event is chosen from the perspective of the source of the event. From this, we choose the name of the event to be “fullViewPossibleChanged” and expect it to contain a boolean as an event argument. To test the eventing support in WinJS, we run the application and type the following in the JavaScript console

and the callback fires, which prints “Hello Jayway” in the console. First feedback cycle is complete.

Refactoring, moving “hide”

Blend's Interactive Mode is your friend

We would like to open Blend and run the app in “Interactive mode”, which would give us rapid feedback on the code changes, but currently Blend does not support the “right click brings up the app bar” feature out-of-the-box (issue 1.3.3.31). I had some issues getting the proposed fix to work and it seems very unstable at the moment. At the moment, we need to hit F5 in VS everytime we want feedback, but hopefully the bug is changed in future versions of Blend so that we can get feedback “for free”. So, in the rest of the post, when I write run/reload, imagine that you just can stay in the Interactive Mode in Blend and see your changes live.

Update: It is also possible to reload the app in the studio, check the Build-menu. Very useful! :)

In itemsPage.js, we comment out the following lines and run/reload the app again.

The app bar now shows the button, as expected.

We then copy the event registration to default.js and replace the log call with the code for hiding the button.

After that, we add the line for queueing the event in itemsPage.js

When we run/reload the app again, the button is no longer visible. Success!

One place left to refactor to move all the “hide” logic: detailsPage.js. We do exactly the same thing, comment out the code hiding the button, run/reload the app and see that button is there, add the code for queueing the event, run/reload the app again and see that the button is no longer there when navigating to detailsPage.html.

Refactoring, moving “show”

At this point, I’m getting more confidence that my mental model matches the reality, which means that I can start to make bigger steps. I add another temporary event handler in default.js,

And I comment out the following code in splitPage.js and add the line that queues the event

Then I run/reload the app and sees that button is still being shown in splitPage.html.

Refactoring, joining the event handlers

We want to join the two event handlers to one event handler, which match the design decision we did in the beginning that we would send a boolean as event argument. Being very confident now, we remove the temporary event handler and change the original one to

We then adds the argument “isFullViewPossible” to all three call sites – splitPage.js sends true and the other two sends false. We run/reload the app and see that it works as we expected.

Refactoring, cleaning up

Before we can consider our selves as done, we remove the out commented code. In default.js, we replace WinJS.Application with the variable name “app”, which was already is scope. Then we run/reload the app again, no changes.

Summary

There are a couple of thing that we notice here. First, we did an early design decision that the event should have a boolean sent with it, but we didn’t need to use the boolean until we joined the two event handlers. In retrospect, I’m not very happy with that strategy – I should have chosen either to use the boolean argument directly in the “hide” refactoring or I should have ignored my “boolean idea” and used two separate events with good names and then joined them in a later refactoring.

I could also have written the two event handlers directly in default.js and using the console to test that they worked, thus creating a “stepping stone” that I could use from the other JavaScript files. Right now, that seems to have been the shortest path to done.

Another thing to notice is that I need to build and deploy the app every time I need feedback of a code change, since I couldn’t use Blend for this refactoring, for reasons stated early in this post. Using automatic tests (unit tests) is of course another option for getting feedback, but AFAIK it’s still not known how to write and run tests against Metro apps written in HTML5. Hopefully there will be a better unittest story for Metro apps written in HTML5 in the near future.

And there are still things to refactor regarding  the appbar logic, i.e. the event listener on the button itself is set by splitPage.js, which is also breaking the encapsulation. Thus, we should in some way move parts of the logic to default.js.

Resources

GitHub repo with the finished example: https://github.com/gustafnk/FeedReaderTechDays2012
Lots of resources on how to develop Metro apps with HTML5:  http://www.jayway.com/2012/04/27/windows-8-for-web-developers-techdays-2012-debriefing/
API reference for WinJS.Application: http://msdn.microsoft.com/en-us/library/windows/apps/br229774.aspx
Responsive Design: http://pragprog.com/magazines/2009-09/responsive-design

One Response to “Custom events in WinJS”

  1. [...] post I will discuss on how to create the target app capable of receiving the shared data.”Custom events in WinJS (Jayway Team Blog)“In this post, we’ll perform a refactoring that moves some code that [...]

Leave a Reply