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
This is helpful: https://cljs.info/cheatsheet/
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"))