boss-level.com
30Jul/115

Most Basic ClojureScript GUI

Introduction

This post is out-of-date. Don't do this anymore.

This quick blog post shows a minimal setup to create a GUI using Clojurescript and the Closure Library GUI functions. In addition shows a working setup wrt directories and the compiler. I'm a web-weenie so this stuff wasn't obvious to me, I hope its helpful. I have put up a git repo for this demo here.

Setup

Directories

The Clojurescript compiler seems to expect files and directories to be in a certain order. This structure works and is sane:

-- root   : put .html file here, compiled .js will go here too
   |     
   +- src   : put .cljs here
   |
   +- out   : compiled Closure will go here
   |  
   +- css   : put stylesheets here

Compiler

Running the cljsc from the terminal is too slow. My minimalist solution is to run a clojure repl from the clojurescript (not project) directory and recompile manually from there. I have added jline to the java classpath to make this easier. Just grab jline-1.0.jar and put into ./lib, then amend ./script/repl to

 java -server -Xmx2G -Xms2G -Xmn256m -cp 'lib/*:src/clj:src/cljs' jline.ConsoleRunner clojure.main

Line up the appropriate incantation, in my case its

 (require '[cljs.closure :as cljsc])
 (cljsc/build 
    "/scratch/clojurescript/hello/src" 
    {:output-dir "/scratch/clojurescript/hello/out" 
     : output-to  "/scratch/clojurescript/hello/hello.js"}) 

So each time I update the .cljs file, I go to the terminal, hit up-arrow, it recompiles, go to web browser and refresh. Its not great, and there are better ideas out there, but it works.

Closure Library GUI

Using the Closure Library GUI was not natural for me, being a web-weenie. The most complete documentation is the source code and accompanying demos. Grab it from the subversion repo

svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only 

You'll find the source code in the

closure-library-read-only/closure/goog/ui

directory. What you really want however are the demos, which are in the

closure-library-read-only/closure/goog/demos/index.html

directory. Point your browser there. The best way I found to get grips with this is to trawl the source for the various demos.

Clojurescript GUI Demo

This is a small barebones demo to show what is necessary to get things hooked up.

Getting this stuff going is a little tricky as you need to identify the correct .css files to import into your .html file and the correct .js files to import into your .cljs. Again, trawl the demos to figure it out.

The HTML file

You'll find hello.html in the root of the repo. This is what the browser loads up. The structure of the file is as follows

  1. Load the appropriate .css files with
    
    ...
    

    tags block. You need common.css for all Closure Library widgets. You don't need demo.css, but I put it in because I like the colours. Then you need a .css for each of the widgets you are using. Its a bit messy figuring out which is which as they don't correspond 1-to-1. Again, look at the demo and copy. I've put the full set of Google provided widget css files into the ./css/ directory for easing this.

  2. Load the appropriate .js files with
    
    
    
      goog.require('hello');
    
    

    type tags. (Please excuse the use of scrjpt for script, wordpress wouldn't ignore the tags!) You need base.js from the Google Library. You'll see this is in the ./out directory, and it gets placed there by the Clojurescript compiler. Worry no more about it. Then you need the .js file that Clojurescript will compile from your .cljs file. It will end up in the root directory.

  3. Construct the DOM structure of your page with the
    ...

    type tags. You'll notice the buttons are done one way and the tab browser another. More on this later.

  4. Finally call the Javascript you have compiled from your Clojurescript
    
    

The Clojurescript File

  1. First load up the required .js files. You can figure them out from the associated goog.require() calls in the demos.
    (ns hello
      (:require
       [goog.dom :as dom]
       [goog.object :as goog-object]
       [goog.events.EventType :as goog-event-type]
       [goog.ui.ColorButton :as color-button]
       [goog.ui.Tab :as gtab]
       [goog.ui.TabBar :as gtabb])) 
    
  2. Instantiate the Library objects
    (def database-button (doto (goog.ui.ColorButton. "Database")
                     (.setTooltip "Database Connection Status")
                     (.setValue "red")))
    
    (def messaging-button (doto (goog.ui.ColorButton. "Messaging")
                            (.setTooltip "Messaging Connection Status")
                            (.setValue "red")))
    
    (def tabbar (goog.ui.TabBar.))
    

    Yeah, looks a lot like Clojure to me too.

  3. Connect these objects to the HTML DOM.
    There are two ways of doing this with Closure Library: rendering and decorating. The former creates a DOM in the .js code and then attaches it to the DOM in the HTML at the .render call. The latter creates the DOM in the HTML at loading, and the object attaches to that. The former keeps the presentation and control logic in the javascript side, the latter separates them; choose your poison. I have rendered the buttons and decorated the tab bar to give examples of both. Either way issue

     (.decorate tabbar (.getElement goog.dom "top"))
    

    This attached the object tabbar, constructed earlier, to the DIV in the html with id "top". Easy peasy.

  4. Wire up the event logic.
    ;;  The database button
    (.listen goog.events
               database-button
               goog.ui.Component.EventType/ACTION
               (partial handle-button-push
                        database-connected?))
    

    Pretty obvious. Attach an event listener to the ACTION event of the object database button and call the function handle-button-push. That function just toggles some internal state to change the colour of the pushed button. You'll notice that handler code looks rather like Clojure; happy days.

Output

Now compile the .cljs using the incantation given earlier and point your browser at the hello.html page. You'll see this, with luck. Clicking the buttons will toggle the colour between red and green
Clojurescriptdemo

Gotchas

The main block I ran into (and was resolved in -5 seconds by triyo on #clojure, thanks dude) was the interop difference from Clojure. Where in Clojure you write

(.method Object)

this will return the source code of the associated method in Clojurescript. Imagine my surprise. Instead go with

(. Object (method))

You'll see examples of this on lines 32 and 33 of the hello.cljs file.

This is mentioned in the docs.

Comments (5) Trackbacks (0)
  1. Thanks for taking the time to document this. Having another working example is a great help.

  2. Thanks for the excellent example. This does take time to wrap your head around, and your example based on a google closure example was very helpful.

    I forked your repo and have added the checkboxes for hiding/showing the hello tab and enable/disable the Advanced tab. it is available at

    https://github.com/rditmore/Minimal-Clojurescript-GUI-Demo

    Looking forward to studying your next post!

  3. will this work in ie8? i’m trying to rule out some possible problems with our application and one of them you use in your example. if yours works in ie8, then that’s not the problem.

  4. Given the age of this post what is the current view of whether Clojurescript is a viable technology? If so is this still the recomended approach?


Leave a comment

Trackbacks are disabled.