INDEX | HOME

Mini Doc - ClojureScript Notes

Table of Contents

This article is a collection of miscleaneous notes on Clojurescript.

1. How to call out to a function?

If you want to setup functions to be called on certain events, there are two ways to do that:

1.1. specify namespace

You can directly call to a function from the HTML if you prefix the function name with it's namespace.

Here is an example using onclick (edit "appname"):

      <div id="functiontest">
        <input id="mynumber" type="number">
        <button onclick="appname.core.timesfive()">times 5!</button>
        <p id="equals"></p>
      </div>  
(defn timesfive
  "multiplies the supplied number by 5 and renders it onto the page"
  []
  (let [number (.-value (.getElementById js/document "mynumber"))
        paragraph (.getElementById js/document "equals")]
    (set! (.-innerHTML paragraph) (* number 5))))

Note that if there are any hyphens in your namespace or function names, replace them with underscores.

1.2. attach listener

This way we attach a listener to the button from code using .addEventListener:

      <div id="functiontest">
        <input id="mynumber" type="number">
        <button id="mybutton">times 5!</button>
        <p id="equals"></p>
      </div>  
(defn byid
  "shortcut for getting element by id"
  [id]
  (.getElementById js/document id))

(defn timesfive
  "multiplies the supplied number by 5 and renders it onto the page"
  []
  (let [number (.-value (byid "mynumber"))
        paragraph (byid "equals")]
    (set! (.-innerHTML paragraph) (* number 5))))

(let [button (byid "mybutton")]
  (.addEventListener button "click" timesfive))

2. How to share code between server and client?

So you want to write some code which will be available to both server and client.

This is fairly simple, we just make a new source directory and add it to both the Clojure and ClojureScript source-paths.

The convention for naming is:

extension type
clj Clojure
cljs Clojurescript
cljc Platform-independant code

As there is no particular "entry-point" for the cljc, so you can simply import it into your Clojure or ClojureScript as you wish.

If you have to include platform-specific code, you may use Reader Conditionals.

3. General notes

3.1. Interop

This example demonstrates calling a function, reading a property, and setting a property:

   (let [myinput (.getElementById js/document "myinput")
         myvalue (.-value myinput)]
     (set! myvalue "foobar"))

n.b. there are multiple ways to do everything. See this article for more examples: ClojureScript <-> JavaScript Interop

3.2. js/ namespace

In the examples we used js/document. But the js/ namespace passes through to JavaScript so you may also access other javascript objects, e.g:

  • js/document
  • js/window
  • js/console
  • js/formdata

And you can also using it to access libraries. For example if using htmx:

  • js/htmx

3.3. this

If you need to access javascript's "this" object, just wrap it with:

   (this-as this
     )

3.4. log to console

(:require [cljs.pprint :refer [pprint]])

3.5. cheat-sheet

3.6. adding reagent

Should you want to add reagent, it builds on-top of what we've already done. Simply:

Add the dependencies:

[reagent "1.2.0"]              
[cljsjs/react "18.2.0-1"]      
[cljsjs/react-dom "18.2.0-1"]] 

Add a div:

<div id="reagentdiv"> 
</div>                

Import reagent to your script :require:

[reagent.core :as r] 
[reagent.dom :as dom]

And render a Hello World:

(dom/render                                                  
 [:div {:id "hello" :class "content"} [:h1 "Hello, Reagent"]]
 (.getElementById js/document "reagentdiv"))                 

Copyright 2024 Joseph Graham (joseph@xylon.me.uk)