I have a "Hello, World!" app in ClojureScript using Om (generated from the "Chestnut" lein template).
The goal is to have it set up such that:
- The
document.location.hash
value reflects changes to the(:route app-state)
vector. - The
(:route app-state)
vector reflects changes to thedocument.location.hash
value. - The app re-renders when
(:route app-state)
changes.
Note that I intend for the (:route app-state)
vector to be the only source of truth for the app about the app's current state. One mechanism of changing it is by the user modifying the url.
Where and how should I attach this behavior to Om?
Here's my "Hello, World!" app.
(ns demo.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[clojure.string :as string]))
(defonce app-state (atom {:text "Hello, World!"
:route ["some" "app" "route"]}))
(defn update-location-hash [app owner]
(reify
om/IRender
(render [_]
(set! js/window.location.hash
(string/join "/" (flatten ["#" (:route app)])))
(dom/div nil ""))))
(om.core/root
update-location-hash
app-state
{:target (. js/document (getElementById "app"))})
(defn main []
(om/root
(fn [app owner]
(reify
om/IRender
(render [_]
(dom/h1 nil (:text app)))))
app-state
{:target (. js/document (getElementById "app"))}))
This successfully writes the document.hash
on page load. Eventually this will be a single-page app that uses hash navigation to make view changes.
This feels dirty to me because of having to return a DOM element in the (render )
function of update-location-hash
that doesn't have any purpose other than to fulfill the requirements of the render
function.