Yesod and Angular JS (and Fay)

By John Lenz. December 16, 2013.

Recently I have been investigating the best way of integrating AngularJs into a Yesod application. For a while I considered adding the Angular code into Yesod widgets, but I have settled on using the new embedded static subsite so that the Angular code is managed separately from the Yesod handlers and widgets. What I particularly like about this approach is its testability. One of the key design philosophies of Angular is to make testing easy. I was pleasantly surprised how easy it is to use the already developed testing tools with only a little glue code that I had to write.

As of Dec 16, 2013 the code is not yet on Hackage. It can currently be found in the yesod-static-generators package, which includes both the generator and an example application. I plan on sticking it on Hackage soon, once I get some feedback on which final package it should be in.

Several things in Angular can be done in more than one way because Angular supports a whole range of server and framework technologies. For the Angular code to be integrated into a Yesod application by my static generator, the Angular code must be written in a certain style (and these sometimes conflict with example Angular code you find around the web). Therefore, if you are just learning Angular I suggest you experiment with Angular outside of Yesod so that you can follow along with the online examples and the Angular guide directly. Once you get somewhat familiar (don't need to be an expert) you can then start integrating Angular into a Yesod application, keeping in mind that sometimes you must adapt examples from the Angular guide and elsewhere around the web so that they work with this generator.

The design

Angular's philosophy (see in particular the section on the Zen of Angular) is to create a domain specific language (DSL) which extends HTML and then to use this DSL to write the views. The views and the Javascript creating this DSL should be kept separate. For integrating Angular and Yesod, this is done as follows.

The key in this design is that the Angular static generator manages the Angular code during compile time and that the view in the Yesod handlers can take advantage of the Angular DSL by just referencing a single script file inside the static subsite.


You might ask what about Fay (or ghcjs)? The static generator (at the moment) only supports Angular code written in pure Javascript. There are some experimental Fay bindings but they are incomplete. This actually isn't that bad for the following reason. Angular controller and directive code seems hard to write in Fay because of an impedance mismatch. That is, the directive and controller code has a declarative flavor; the directive code is mostly configuration and the controller code just sets up the scope. The directive code focuses only on manipulating the DOM for just the single directive, and the controller adds things to the scope but should not implement any complex logic itself. Because of this, controller and directive code does not need any of the bad parts of Javascript that make using Javascript so frustrating.

In a typical Angular application, the controllers and directives have this narrow focus and the bulk of the logic is therefore located in services. This is where the code which communicates with the server using AJAX is located. Also, the code which implements the data validation, transformation, and business logic. This service code is a great candidate for writing in Fay. Recent versions of Fay support a strict mode that allows Fay code to be called from Javascript. Thus, we can write the bulk of the complex logic/data manipulation code in Fay/Haskell without needing any detailed Angular bindings (e.g. the code communicating with the server using AJAX doesn't need anything Angular specific). We can then call these Fay functions from our Angular controllers/directives written in pure Javascript, and these controllers basically just wire up the scope with the Fay functions so can be small.

Of course at some point replacing everything by Fay would be nice and I have some thoughts on how this might look, but for now I am concentrating on using Fay for services and pure Javascript for controllers and directives.


A major goal of Angular is to make the code easy to test (as long as the right tools are in place). Designing the application as mentioned above fits nicely with the available testing tools. I discuss these tools in the next post.