Tag Archives: JavaScript

Direct Server HTTP Calls in Protractor

When you’re running end-to-end tests, chances are that sometimes you need to set up the system before running the actual test code. It can involve cleaning up after previous executions, going through some data setup “wizard” or just calling the raw server API directly. Here’s how you can do it with Protractor.

Protractor is a slick piece of technology that makes end-to-end testing pretty enjoyable. It wires together Node, Selenium (via WebDriverJS) and Jasmine, and on top of that it provides some very useful extensions for testing Angular apps and improving areas where Selenium and Jasmine are lacking.

To make this concrete, let’s say that we want to execute two calls to the server before interacting with the application. One of them removes everything from database, another kicks off a procedure that fills it with some well-known initial state. Let’s write some naive code for it.

Using an HTTP Client

var request = require('request');

describe("Sample test", function() {
    beforeEach(function() {
        var jar = request.jar();
        var req = request.defaults({
            jar : jar
        });

        function post(url, params) {
            console.log("Calling", url);
            req.post(browser.baseUrl + url, params, function(error, message) {
                console.log("Done call to", url);
            });
        }

        function purge() {
            post('api/v1/setup/purge', {
                qs : {
                    key : browser.params.purgeSecret
                }
            });
        }

        function setupCommon() {
            post('api/v1/setup/test');
        }
        
        purge();
        setupCommon();
    });

    it("should do something", function() {
        expect(2).toEqual(2);
    });
});

Since we’re running on Node, we can (and will) use its libraries in our tests. Here I’m using request, a popular HTTP client with the right level of abstraction, built-in support for cookies etc. I don’t need cookies for this test case – but in real life you often do (e.g. log in as some admin user to interact with the API), so I left that in.

What we want to achieve is running the “purge” call first, then the data setup, then move on to the actual test case. However, in this shape it doesn’t work. When I run the tests, I get:

Starting selenium standalone server...
Selenium standalone server started at http://192.168.15.120:58033/wd/hub
Calling api/v1/setup/purge
Calling api/v1/setup/test
.

Finished in 0.063 seconds
1 test, 1 assertion, 0 failures

Done call to api/v1/setup/purge
Done call to api/v1/setup/test
Shutting down selenium standalone server.

It’s all wrong! First it starts the “purge”, then it starts the data setup without waiting for purge to complete, then it runs the test (the little dot in the middle), and the server calls finish some time later.

Making It Sequential

Well, that one was easy – the HTTP is client is asynchronous, so that was to be expected. That’s nothing new, and finding a useful synchronous HTTP client on Node isn’t that easy. We don’t need to do that anyway.

One way to make this sequential is to use callbacks. Call purge, then data setup in its callback, then the actual test code in its callback. Luckily, we don’t need to visit the callback hell either.

The answer is promises. WebDriverJS has nice built-in support for promises. It also has the concept of control flows. The idea is that you can register functions that return promises on the control flow, and the driver will take care of chaining them together.

Finally, on top of that Protractor bridges the gap to Jasmine. It patches the assertions to “understand” promises and plugs them in to the control flow.

Here’s how we can improve our code:

var request = require('request');

describe("Sample test", function() {
    beforeEach(function() {
        var jar = request.jar();
        var req = request.defaults({
            jar : jar
        });
        
        function post(url, params) {
            var defer = protractor.promise.defer();
            console.log("Calling", url);
            req.post(browser.baseUrl + url, params, function(error, message) {
                console.log("Done call to", url);
                if (error || message.statusCode >= 400) {
                    defer.reject({
                        error : error,
                        message : message
                    });
                } else {
                    defer.fulfill(message);
                }
            });
            return defer.promise;
        }
		


        function purge() {
            return post('api/v1/setup/purge', {
                qs : {
                    key : browser.params.purgeSecret
                }
            });
        }

        function setupCommon() {
            return post('api/v1/setup/test');
        }
		
        var flow = protractor.promise.controlFlow();
        flow.execute(purge);
        flow.execute(setupCommon);
    });

    it("should do something", function() {
        expect(2).toEqual(2);
    });
});

Now the post function is a bit more complicated. First it initializes a deferred object. Then it kicks off the request to server, providing it with callback to fulfill or reject the promise on the deferred. Eventually it returns the promise. Note that now purge and setupCommon now return promises.

Finally, instead of calling those functions directly, we get access to the control flow and push those two promise-returning functions onto it.

When executed, it prints:

Starting selenium standalone server...
Selenium standalone server started at http://192.168.15.120:53491/wd/hub
Calling api/v1/setup/purge
Done call to api/v1/setup/purge
Calling api/v1/setup/test
Done call to api/v1/setup/test
.

Finished in 1.018 seconds
1 test, 1 assertion, 0 failures

Shutting down selenium standalone server.

Ta-da! Purge, then setup, then run the test (again, that little lonely dot).

One more thing worth noting here is that control flow not only takes care of executing the promises in sequence, but also it understands the promises enough to crash the test as soon as any of the promises is rejected. Once again, something that would be quite messy if you wanted to achieve it with callbacks.

In real life you would put that HTTP client wrapper in a separate module and just use it wherever you need. Let’s leave that out as an exercise.

“Mastering Web Application Development with AngularJS” (Book Review)

While the first demos and tutorials of AngularJS make very good impression, using it on your own in real life applications quickly leads to confusion and frustration. You soon discover that the documentation falls short of explaining what really is going on, especially in the more advanced areas. It does not do a very good job at showing idiomatic usage either – with proper separation of responsibilities, use of services and directives, etc.

“Mastering Web Application Development with AngularJS” by Paweł Kozłowski and Peter Darwin is really good resource to fill those gaps. It starts with a decent explanation of what AngularJS is all about. How DOM is some kind of a skeleton behind the application, or in other words how application state is directly reflected in DOM. Right after this introduction it introduces unit testing, and from this point on everything is demonstrated not only with the “production” code, but also with accompanying test suites.

Then it starts to dig a bit deeper – from filters, communcation with back-end and navigation through writing custom directives and performance. While the beginning seems to be a bit slow, the chapters on directives are really detailed, have plenty of great examples and do an outstanding job at explaining this difficult subject. Actually, I would say that the whole book may be a bit too advanced for beginners, but then even if you have some experience with Angular, it is well worth reading for the directives alone.

The entire book is organized as a systematic “reference”, with each chapter dedicated to one aspect of the framework: Binding and filters, communication with server, forms, navigation and routing, directives, internationalization, build/deployment, and so on. There also is a complete non-trivial application available on Github, and referenced throughout the book. Each and every aspect has a very accessible and complete explanation. Theory and rationale, working code as well as test suites.

In other words, the book is not a simplistic tutorial, but a detailed study that takes a reasonably complex application and dissects it one “dimension” at a time. You don’t need to study the entire application while reading the book, but it’s a great complementary material that demonstrates how the pieces fit together and is a ready-to-use cookbook of some sort.

If there is anything missing, I would say it’s information on idiomatic usage: How you are supposed to structure your application, divide it into modules and services, and so on. Not that it’s completely missing from the book, but a bit of a bird’s-eye view would be nice as well.

All in all, it’s definitely worth reading. Detailed, non-trivial, doing a great job at explaining the “why’ and demonstrating the “how”.

(I got the book directly from Packt and read it on Kindle – nothing to complain about in this edition, everything readable and comprehensible.)

Client-Side Routing with Pedestal

It’s fairly common for rich web applications to use some kind of client-side routing: Load the application once, then navigate with special URLs like http://example.com/#/subpage. Browser doesn’t perform a round trip to server for them, but instead the right chunk of JavaScript can rebuild part of the page locally, hide and show elements etc.

JavaScript tools

There is a number of JavaScript tools to do it. I find two examples particularly inspiring.

Flatiron Director lets you do something like:

var author = function () { console.log("author"); };
var books = function () { console.log("books"); };
 var routes = {
  '/author': author,
  '/books': books
};</p>

<p>var router = Router(routes);
router.init();

Then when you visit page ending with #/books, it will call the books function. Very flexible, but then you need to write a lot of code yourself.

Another good example with completely different philosophy is the Angular JS Router. In your page you can bless a special section as the ngView, and configure router with:

$routeProvider
    .when('/author', {templateUrl: '/t_author.html', controller: "authorController"})
    .when('/books', {templateUrl: '/t_books.html', controller: "booksController"})
    .otherwise({redirectTo: '/books'});

When you go to #/author, Angular will replace the contents of ngView with the template and install the selected controller on it. It fits well in the Angular philosophy and has some benefits.

Pedestal

Anyway, how can we use routing with Pedestal? Turns out there is no built-in or even recommended way to do it, but you can plug in whatever you want. After some research I decided to use goog.History from Closure which comes free of charge with ClojureScript.

All code for these examples is in my GitHub repository. Note that there are 3 tags corresponding to each of the solutions.

Attempt 1: Simple, hardcoded

The first thing I did was a rather ugly, hardcoded solution using the entire Pedestal data flow.

First I installed a listener on goog.History that extracts the location token and pushes it to the :route topic in Pedestal input queue:

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

(defn configure-router 
  ([input-queue] (configure-router input-queue ""))
  ([input-queue default-route]
    (doto (goog.History.)
      (goog.events/listen (goog.object/getValues goog.history/EventType) 
                          (fn [e]
                            (let [token (.-token e)]
                              (if (= "" token)
                                (set-route input-queue default-route)
                                (set-route input-queue token)))))
    (.setEnabled true))))

I plugged in the default transform and emitter that basically push that message up to the application model:

(def count-app {:transform {:route {:init nil :fn #(:value %2)}}
                :emit {:router {:fn app/default-emitter-fn :input #{:route}}}})

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

The last step on the pipeline is renderer. This one here is fairly uninteresting, it basically replaces contents of some specific div with different text:

(defn route-changed [_ [_ _ old-value new-value] input-queue]
  (.log js/console "Routing from" old-value "to" new-value)
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" new-value "</p>"))))

The main function:

(defn ^:export main []
  (let [app (app/build count-app)
        render-fn (push/renderer "content" [[:value [:route] route-changed]])]
    (render/consume-app-model app render-fn)
    (configure-router (:input app) "first")
    (app/begin app)))

This solution is hardly reusable, but it’s also very flexible. At any point we can decide to do something specific when switching the location – change something in data or application model, make a server request, etc.

I wouldn’t recommend it, it’s just the very first attempt at the problem.

Attempt 2: Generic

It’s quite obvious that the above solution can be generalized. One way to do it is to generalize the renderer. We can initialize it with some configuration telling it what action to execute for each path. For instance, something like this:

(defn render-route [msg]
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" msg "</p>"))))

(defn route-first []
  (render-route "This is the first route"))

(defn route-second []
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [old-value new-value]
               (.log js/console "Routing from" old-value "to" new-value))})

There isn’t too much interesting stuff happening here, but it clearly is more reusable.

The renderer is now initialized with this config like:

(defn route-renderer [cfg]
  (fn [_ [_ _ old-value new-value] input-queue]
    (when-let [listener (:listener cfg)]
      (listener old-value new-value))
    (if-let [dispatcher (get-in cfg [:routes new-value])]
      (dispatcher)
      (.log js/console "Unknown route:" new-value))))

I’ll omit the history listener and main for clarity, but I hope the point is clear. Again, code is at Github under the generic tag.

All this solution does is bind a function call to each path. I could easily extract it to a tiny generic library. I could also make it more powerful – for instance, use higher order “constructor functions” that let each action access state or push to the input queue. I could use templating. And so on.

Attempt 3: Generic – light

As I was wrapping that up, I figured out one more way to do it. Remember, both solutions above use the entire Pedestal stack – the history listener pushes a message to input queue, and we need a transform and emitter to pass it up to renderer. Maybe I don’t need to involve the “lower layers” with navigation and rendering?

I realized I can just plug the rendering in the history listener itself:

(defn route-first [input-queue]
  (render-route "This is the first route"))

(defn route-second [input-queue]
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [new-value]
               (.log js/console "Routing to" new-value))})

(defn route-changed [{:keys [input]} route-config]
  (fn [e]
    (let [token (.-token e)
          token (if (= "" token) (:default-route route-config) token)]
      (when-let [listener (:listener cfg)]
        (listener token))
      (if-let [dispatcher (get-in route-config [:routes token])]
        (dispatcher input)
        (.log js/console "Unknown route:" token)))))

(defn configure-router 
  ([app route-config]
    (doto (goog.History.)
      (goog.events/listen 
        (goog.object/getValues goog.history/EventType) 
        (route-changed app route-config))
      (.setEnabled true))))

(defn ^:export main []
  (let [app (app/build)]
    (configure-router app router-config)
    (app/begin app)))

That’s it. It doesn’t even need Pedestal. The router is a generic little thing based only on Google Closure. However, in this case each action also has access to the input queue and it’s pretty obvious how you could expose any other things from Pedestal. You can still push messages to Pedestal, install renderers etc. – but that’s no longer required for routing itself.

Wrapping Up

In the end, I’m fairly satisfied with the last solution. Well, in a way – it still requires me to do a ton of manual work! Not for the routing itself, but for DOM rendering. It feels a lot like jQuery, with tons and tons of tedious, manual DOM manipulation.

I guess I became a little spoilt by Angular, and I’m already experimenting with marrying the two.

All the time I’m facing friction though – if I let Angular do too much, I don’t really have any use for Pedestal. On the other hand, there is quite some impedance mismatch between the Angular “pull-oriented model” and Pedestal’s differential pushes. If I ever come to any sane conclusions on this front I’ll write that up. But that’s another story.

Angular Tutorial Rewritten to ClojureScript

Over the last few months I learned some more ClojureScript and I finally came back to Angular. First I followed their excellent tutorial. Then I decided to rewrite it to plain Clojure and ClojureScript, and it went pretty well.

I made one change on the go – rather than load JSON files directly from disk, it talks to a Ring-provided service.

Raw files are below:

All code is available at GitHub.

It’s almost a one-to-one rewrite from JavaScript. Compared to the original, it is pretty ugly – for two reasons. The first is that I wanted it to work with advanced Closure compiler, so I had to use explicit dependencies. The second is that there is a lot JavaScript interop.

Many of those issues can be mitigated with a glue layer. It is possible to write functions or macros that would automatically generate array syntax for functions with injected dependencies, create functions automatically converting arguments with clj->js, and provide a better replacement for $scope.property = function(...){...}.

I may do that later, but firstly I wanted to have a one-to-one replacement.

JS Routing: Sammy vs. Flatiron Director

Having little knowledge about client-side routing in JavaScript, I decided to compare two frameworks: Sammy.js and Flatiron Director.

Scope

I’ll do the comparison on a very simple application (loosely based on a sample from Flatiron). The features I’d like to use are:

  • Routing: Routing based on hash URLs like app#/author.
  • Routing with params: Getting parameters from URLs like ?15? from app#/books/15.
  • Multiple bindings: Performing more than one action for a route (in a real app it could be routing and loading some data).
  • Default routes: Plugging in a ?default? route for all unmatched paths.
  • Listeners: Plugging in a listener – some special action to execute in addition to routing on all paths.

Code

Flatiron Director

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Flatiron Director Sample</title>
    <script src="https://raw.github.com/flatiron/director/master/build/director-1.1.6.min.js"></script>
    <script>
    var author = function () { console.log("author"); };
    var books = function () { console.log("books"); };
    var viewBook = function(bookId) { 
      console.log("viewBook: bookId is populated: " + bookId); 
    };
    var wildcard = function(route) { 
      console.log("Wildcard at: " + route);
    };
    var listener = function() { 
      console.log("Listener at: " + window.location); 
    };

    var routes = {
      '/author': author,
      '/books': [books, function() { console.log("An inline route handler."); }],
      '/books/view/:bookId': viewBook,
      '/:def': wildcard
    };

    var router = Router(routes);
    router.configure({ on: listener });
    router.init();
    </script>
  </head>
  <body>
    <ul>
      <li><a href="#/author">#/author</a></li>
      <li><a href="#/books">#/books</a></li>
      <li><a href="#/books/view/1">#/books/view/1</a></li>
      <li><a href="#/other">#/other</a></li>
    </ul>
  </body>
</html>

Sammy.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Sammy Sample</title>
    <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    <script src="https://raw.github.com/quirkey/sammy/master/lib/min/sammy-latest.min.js"></script>
    <script>
    $(function() {
      var author = function () { console.log("author"); };
      var books = function () { console.log("books"); };
      var viewBook = function(bookId) { 
        console.log("viewBook: bookId is populated: " + bookId); 
      };
      var wildcard = function() { 
        console.log("Wildcard at: " + this.params['route']);
      };
      var listener = function() { 
        console.log("Listener at: " + this.params['path']);
      };

      $.sammy("#main", function() {
        this.get('#author', author);
        this.get('#books', books);
        this.get('#books/view/:id', function() {
          viewBook(this.params['id']);
          console.log("An inline route handler.");
        });
        this.get('#:route', wildcard);
        this.bind('run-route', listener);
      }).run('#');
    });
    </script>
  </head>
  <body id="main">
    <ul>
      <li><a href="#author">#author</a></li>
      <li><a href="#books">#books</a></li>
      <li><a href="#books/view/1">#books/view/1</a></li>
      <li><a href="#other">#other</a></li>
    </ul>
  </body>
</html>

Notes

So what do I think about them?

Director seems to be fairly lightweight and simple. It has no dependencies and weighs 3.7 kB. It?s almost functional programming (except for the moment when you turn it on) – you can immediately see what?s going on and what the options are.

In comparison, Sammy.js is much heavier. It depends on jQuery (32.7 kB) and it weighs 6.5 kB. It makes more assumptions: Your code needs to run after page is loaded (that?s why it?s wrapped in $.ready here). It makes you write OO code – functions have no arguments, but you get more information exposed on this.

Director supports plugging in multiple handlers to a route out of the box (you can pass an array of functions). In Sammy apparently you need to wrap them in another function.

For some reason Director seems to require URLs to have a slash, like app#/books – never app#books. Sammy does not care.

The rest you can see for yourself in the code above.

Verdict

Sammy makes me download more code, all the time I need to read documentation (“So what parameters are available here?”, “What does this object hide?”), and in the end it even makes me write more code. Look at the parameterized viewBook handler: With Director, I can add the parameter to handler function and it just works. With Sammy I need to get it from this.

At this point I have strong preference for the Director. It’s smaller and much easier to use. I like that even more because I can directly use it from ClojureScript with minimal friction. It would take quite an effort to integrate Sammy.

Using Angular.js with ClojureScript

When I wrote my last post on ClojureScript, I was really hoping someone would jump in and say: “You’re doing it wrong! Here’s how.”

I did get some interesting replies, especially on HackerNews (where that post was briefly on the front page). There really seem to be two camps here: Newbies as confused as I am, and pros who say you just have to invest the time and learn, then you may be able to make good use of some of existing JS frameworks or (better?) roll your own ClojureScript frameworks. They say it’s worth it once your codebase is big enough.

Getting Angular to Work

Anyway, Greg Weber here on my blog noted that you can actually use Angular with Closure – just need to use explicit dependency injection. So far Angular seemed to require the least work with CLJS, so I was happy to give it another shot. I also found this note on minification in Angular docs very helpful.

In the end I’ve successfully rewritten the “todo” sample application. Here’s one way to do it:

(defn add-todo [scope]
  (fn []
    (.push (.-todos scope) (js-obj "text" (.-todoText scope) "done" false))
    (aset scope "todoText" "")))

(defn remaining [scope]
  (fn [] 
    (count (filter #(not (.-done %)) (.-todos scope)))))

(defn archive [scope]
  (fn []
    (let [arr (into-array (filter #(not (.-done %)) (.-todos scope)))]
      (aset scope "todos" arr  ))))

(defn CTodoCtrl [$scope]
  (def $scope.todos (array (js-obj "text" "learn angular" "done" true)))
  
  (def $scope.addTodo (add-todo $scope))

  (def $scope.remaining (remaining $scope))

  (def $scope.archive (archive $scope))) 

(def TodoCtrl
  (array
    "$scope"
    CTodoCtrl))

The last 4 lines are equivalent of using this array syntax in JavaScript:

TodoCtrl = ['$scope', CTodoCtrl];

Another way to do it is setting the $inject property, like this:

(def TodoCtrl CTodoCtrl)
(aset TodoCtrl "$inject" (array "$scope"))

As usually, complete working project can be found at my GitHub repository.

Implementation Details

Function definition

In the above example I’m defining functions on CTodoCtrl by using “factory functions”. I find this slightly more readable, but it also can be done with in-place definitions like this:

(aset $scope "remaining" 
        (fn []
          (count (filter #(not (.-done %)) (.-todos $scope)))))

Unfortunately, I was unable to get it to work with anonymous functions (it compiled to CTodoCtrl.remaining = (function CTodoCtrl.remaining() {...):

(aset $scope "remaining" #(...))

This did not work either (I wish it did!):

(defn $scope.remaining [] (...))

Objects, Arrays

I’m not quite happy with the use of objects here – I would definitely prefer to use Clojure maps like this:

; Instead of:
; (def $scope.todos (array (js-obj "text" "learn angular" "done" true)))
; Do:
(def $scope.todos [{:text "learn angular" :done true}])
; Insetad of:
; (into-array (filter #(not (.-done %)) (.-todos scope)))
; Do:
(filter #(not (:done %)) (:todos scope))

Unfortunately, it seems Angular doesn’t like ClojureScript types and vice versa. Looks like a small, fixable annoyance.

ClojureScript!

It’s still ugly at places and not quite spectacular, but I like using functional programming with ClojureScript instead of JavaScript loops.

I mean replacing this:

var count = 0;
angular.forEach($scope.todos, function(todo) {
  count += todo.done ? 0 : 1;
});
return count;

with:

(count (filter #(not (.-done %)) (.-todos scope)))

And this:

var oldTodos = $scope.todos;
$scope.todos = [];
angular.forEach(oldTodos, function(todo) {
  if (!todo.done) $scope.todos.push(todo);
});

with:

(let [arr (into-array (filter #(not (.-done %)) (.-todos scope)))]
      (aset scope "todos" arr))

Verdict

All in all, I may finally be seeing the light at the end of the tunnel. Integration with Angular looks very promising, after addressing the small interop glitches with type mapping it may be quite expressive and straightforward. I probably will shelve Knockout for now and explore Angular.

Marrying ClojureScript and JS Frameworks – Knockout Edition

A while ago I began to play with ClojureScript and tried to get it to work with popular frameworks. I played with a few of them, most recently with Knockout.js. This post sums up those efforts and my not-so-optimistic view on ClojureScript.

  • I tried “bare” jQuery. It was pretty smooth.
  • I tried Backbone.js. I got it to work on a simple example, though one reader on Twitter rightfully commented that ClojureScript was hideous. Yes, that Backbone example is hideous. Later on I tried to do something less trivial. Eventually I fled in horror, thanks to impedance mismatch between heavily OO Backbone and non-OO ClojureScript sauced with my ignorance in CLJS (and Backbone).
  • I also gave Angular.js a shot. It started really smooth, because Angular proudly states that it doesn’t rely on object-oriented programming so much. It was great. Right to the moment when I started arguing with the compiler renaming my variables, soon followed by discovery that Angular and Closure are no go.

So, the time has come to another experiment – this time Knockout.js. I followed the official tutorial and here is what I eventually came up with.

The Page

The complete page in Hiccup looks like this. Nothing particularly exciting here.

(defn render-body []
  (hp/html5
     [:head]
     [:body
 
      [:p "First name: " [:strong {:data-bind "text: firstName"} "todo"]]
      [:p "Last name: " [:strong {:data-bind "text: lastName"} "todo"]]
      [:p "Full name: " [:strong {:data-bind "text: fullName"} "todo"]]
      
      [:p "First name: " [:input {:data-bind "value: firstName"}]]
      [:p "Last name: " [:input {:data-bind "value: lastName"}]]
      
      [:button {:data-bind "click: capitalizeLastName"} "Go caps"]
   
      (hp/include-js 
        "//ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js"
        "js/cljs.js")
      (hp/include-css "css/todo.css")
      ]))

ClojureScript

The most interesting part is the ClojureScript code. Here’s one way to do it:

(ns hello-clojurescript)

(defn app-view-model []
  (this-as this
           (set! (.-firstName this) (.observable js/ko "Bert"))
           (set! (.-lastName this) (.observable js/ko "Bertington"))
           (set! 
             (.-fullName this)
             (.computed js/ko 
               (fn []
                 (str (.firstName this) " " (.lastName this))) this))
           (set!
             (.-capitalizeLastName this) 
             (fn []
               (.lastName this (-> this .lastName .toUpperCase)))))
  nil
  )

(.applyBindings js/ko (app-view-model.))

Yes, I do need to explicitly return “nil” there. Otherwise it returns this.fullName = ..., and that breaks KO.

It works, but it’s hard to defend it in comparison to the JS equivalent:

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();    
    }, this);
    this.capitalizeLastName = function() {
        var currentVal = this.lastName();     
        this.lastName(currentVal.toUpperCase());
    };
    
}

ko.applyBindings(new AppViewModel());

Complete code can be found at my GitHub repository.

Better Way – Macro

This code can be made a lot better with a custom macro, as the one presented at StackOverflow:

(defvar name_model
    first_name (observable "My")
    last_name (observable "Name")
    name (computed (fn [] (str (. this first_name) " " (. this last_name)))))

(. js/ko (applyBindings name_model));

Now, that would be something!

… except for that defining macros in ClojureScript is harder than in plain Clojure, to the point that I haven’t gotten it to work yet.

Conclusions on ClojureScript

I spent quite a few hours poking at ClojureScript, and I have mixed feelings.

  1. It’s pretty hard to get ClojureScript to work with existing JS frameworks, mostly because using objects in CLJS requires so much ceremony.
  2. Contrary to plain Clojure, “fun” and “productive” aren’t the words that come to mind when I think of my adventures in CLJS. “Frustrating” and “intimidating” are much more appropriate. I’m constantly arguing with the compiler and trying to beat it to do the right thing, not having fun solving problems.
  3. Some stuff can be covered with macros, but all in all it feels very… rigid and constraining. I feel like every once in a while I’m bound to hit another rough corner, spend too much time on it, write another macro, and so on. All that only to bridge the gaps and make ClojureScript look more like… JavaScript. In fact, that feels like writing my own layer of macros to compile JS-like-DSL to ClojureScript.
  4. Perhaps there is a better way and I’m just doing something wrong. Maybe you’re not supposed to use those frameworks at all, but roll your own or use those few written in ClojureScript?
  5. Perhaps all of this makes little sense on such a small scale, and you need something really big to appreciate ClojureScript. You just need to invest many hours in passing the learning curve and macroing your way out. Maybe then it becomes more productive, modular and whatnot. I don’t know, in fact I have too little experience in JavaScript itself to answer such questions. I’m not very optimistic about it, though.

Hello, Backbone and ClojureScript

A few days ago I started learning ClojureScript. I wrote a trivial “hello world” application just to get ClojureScript to compile and execute, and later added some basic jQuery support with jayq.

The time has come to make things a little bit more interesting and add Backbone.js to the mix. I’ve never done ClojureScript or Backbone before, so I’m learning them at the same time with an interesting learning curve.

Anyway, I managed to rewrite the first two examples from Backbone docs to pure CLJS. I made some minor modifications like triggering events on button click and changing main background instead of sidebar.

Here’s my page source (with Hiccup):

(hp/html5 
  [:head]
  [:body
   [:button#clickable-event "Click to trigger an alert from basic Backbone event"]
   [:button#clickable-color "Click to change background color"]
   (hp/include-js 
     "http://code.jquery.com/jquery-1.8.2.min.js"
     "http://underscorejs.org/underscore.js"
     "http://backbonejs.org/backbone.js"
     "js/cljs.js")
   ])

As you can see, it renders a very basic page with two buttons and includes a few JS libraries.

And here’s the CLJS file mixing jQuery and Backbone:

(ns hello-clojurescript
  (:use [jayq.core :only [$]])
  (:require [jayq.core :as jq]))

; ALERT ON CLICK
; Rewrite of http://backbonejs.org/#Events
(def o {})

(.extend js/_ o Backbone.Events)

(.on o "alert" 
  (fn [msg] (js/alert msg)))

(jq/bind ($ "#clickable-event") :click 
      (fn [e] (.trigger o "alert" "Hello Backbone!")))

; MODEL WITH COLOR CHOOSER
; Inspired by http://backbonejs.org/#Model but without sidebar

(def MyModel 
  (.extend Backbone.Model
    (js-obj 
      "promptColor"
      (fn [] 
        (let [ css-color (js/prompt "Please enter a CSS color:")]
          (this-as this
                   (.set this (js-obj "color" css-color))))))))

(def my-model (MyModel.))
 
(.on my-model "change:color"
  (fn [model color]
    (jq/css ($ "body") {:background color})))

(jq/bind ($ "#clickable-color") :click 
         (fn [e] (.promptColor my-model)))

There’s a number of new things (to me) and nonobvious pitfalls. View this side-by-side with Backbone demos, and note:

  • To invoke _.extend(o, Backbone.Events), do (.extend js/_ o Backbone.Events). ClojureScript will correctly transform (.extend js/_ ...) to _.extend(...), and it will copy Backbone.Events as is (no quoting necessary)
  • To distinguish between objects and functions defined elsewhere and in CLJS, always prefix the former with js/name. Works for alert, underscore etc.
  • I had an issue with passing objects (as maps) directly to calls like Backbone.Model.extend(). Tried things like {:promptColor fn} and {"promptColor" fn} to no avail. I finally discovered (js-obj) and it did the trick, but it’s pretty cumbersome. I wonder if there’s a better way.
  • You need some extra work to use this. It has to be bound to a Clojure symbol with this-as macro.
  • On a slightly related note, I really begin to love jayq. In this example I use bare Backbone directly and struggle, and really appreciate jayq bridging the gap to jQuery. I wonder if there is a CLJS wrapper for Backbone.

All in all, it’s an interesting exercise. Just the right learning curve – stimulating, but not discouraging, regularly providing visible feedback.

As usually, complete source is at GitHub. I created a new repository for it, to keep “hello ClojureScript” as small as possible. This new demo probably will grow as I learn more Backbone.

Hello, ClojureScript! (with jQuery)

I decided to give ClojureScript a try. It did not come easy, because I found the official documentation somewhat complicated. I know there is ClojureScript One, but that project also is not as simple as it could be. I don’t want fancy functionality, noir/compojure, enlive/hiccup, and tons of other semi-relevant tools. Bare simplistic HTML and a starting hook for ClojureScript is pretty much all I need for the head start, I can add the rest later.

I was looking for something really minimal, and the first simple example on my Google search was Daniel Harper’s article. I got rid of noir, used up to date versions of libraries, and voila – it’s working!

When I had my first “hello world” alert showing on page load, I decided to make things a little bit more interesting and introduce jQuery. I found jayq from Chris Granger and decided to give it a shot. There’s also a sample app on Chris’ blog that helped me with some issues, namely figuring out how to bind events. It references a few more interesting libs (namely fetch & crate), but I’ve had enough for now. I guess I could spend the whole night chasing such references.

In the end, the interesting pieces of code are below:

project.clj (configured to compile CLJS from src-cljs to resources/public/js/cljs.js):

(defproject hello-clojurescript "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [ring "1.1.6"]
                 [jayq "0.1.0-alpha3"]]
  :plugins [[lein-cljsbuild "0.2.8"]]
  :cljsbuild
  {
   :source-path "src-cljs"
   :compiler
   {
    :output-to "resources/public/js/cljs.js"
    :optimizations :simple
    :pretty-print true
    }
   }
  :main hello-clojurescript.core
  )

core.clj (trivial app, with Ring wrapper configured to serve JS resources):

(ns hello-clojurescript.core
  (:require [ring.adapter.jetty :as jetty]
            [ring.middleware.resource :as resources]))


(defn handler [request]
  {:status 200
   :headers {"Content-Type" "text/html"}
   :body 
   (str "<!DOCTYPE html>"
        "<html>"
        "<head>"
        "</head>"
        "<body>"
        "<p id=\"clickable\">Click me!</p>"
        "<p id=\"toggle\">Toggle Visible</p>"
        "<script src=\"http://code.jquery.com/jquery-1.8.2.min.js\"></script>"
        "<script src=\"js/cljs.js\"></script>"
        "</body>"
        "</html>")})

(def app 
  (-> handler
    (resources/wrap-resource "public")))

(defn -main [& args]
  (jetty/run-jetty app {:port 3000}))

hello-clojurescript.cljs (this one gets compiled to JavaScript):

(ns hello-clojurescript
  (:use [jayq.core :only [$ delegate toggle]]))

(def $body ($ :body))

(delegate $body :#clickable :click
          (fn [e]
            (toggle ($ :#toggle))))

Complete source code with instructions can be found at my GitHub repository.

At the moment I see the following issues:

  • I’m really green at ClojureScript. Tons to learn here!
  • The JavaScript file compiled from this trivial example is 13k lines long and weighs about 500 kb. Doh! Fine for local development on desktop, not that good for targetting mobile.
  • The official docs for ClojureScript are really… discouraging. Just like core Clojure documentation, they are pretty academic and obscure.
  • Docs for jayq are… Wait a minute, nonexistent? At least it’s a fairly thin adapter with small, comprehensible codebase.