5
votes

I'm developing RIA with clojure and clojurescript. Backend uses hiccup to generate a resulting html, like

(html5 
[:head 
  (include-js "/js/my-cljs-generated.js")]
[:body ... ])

How can I pass edn(hashmap, vector, etc.) to clojurescript within the resulting html, i.e. without doing ajax call?

I would like to make hiccup do something like this:

(include-edn 
   "var_name" {:foo :bar}) ; or any other clojure data

and to be able to access the passed edn from cljs somehow(e.g. by name).

Currently my implementation is a bit hacky and stores edn in a global js var

(hiccup/javascript-tag (str "var edn = \""
                       (pr-str my-clojure-data) "\";"))        

and on cljs side does smth like

(jayq/document-ready 
  (fn []
    (if-let [edn (.-edn js/window)]
      (do-something-with (cljs.reader/read-string edn))
    )
    ...
)

Maybe there is more idiomatic way of achieving this?

3

3 Answers

3
votes

Your approach is fine. If you're concerned about the manual creation of JavaScript code, an alternative would be to put the result of pr-str as data in a well-defined element. Something along the lines of:

[:div {:style {:display "hidden"}
       :id "server-originated-data"
       :data-var-1 (pr-str var-1)
       :data-var-2 (pr-str var-2)}]

You can then get that data from ClojureScript with something like:

(defn get-data
  [tag]
  (-> (.getElementById js/document "server-originated-data")
      (.getAttribute (str "data-" tag))
      (cljs.reader/read-string)))

Though, again, your approach is fine.

1
votes

Your "implementation" is perfectly fine. Wrap it in a function if that makes you feel more comfortable :)

It wouldn't make a difference if you emitted e.g. compiled ClojureScript instead; the value would be still global and mutable.

1
votes

You could consider a push (event-based) approach, rather than pull: place your generated edn data as a string inside a [:script] tag as an argument to a javascript call a clojurescript function. When the script is loaded by the browser it will send the edn to your handler function, allowing it to be loaded by your application.

This would be a little more idiomatic than your current approach as it doesn't require state or global data, and could easily be adapted to use ajax later, if required.