Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass edn to clojurescript from clojure without making ajax request (i.e. via hiccup-generated page)

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?

like image 684
ndrw Avatar asked Mar 15 '13 01:03

ndrw


3 Answers

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.

like image 190
Gary Verhaegen Avatar answered Oct 17 '22 01:10

Gary Verhaegen


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.

like image 26
deprecated Avatar answered Oct 17 '22 00:10

deprecated


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.

like image 22
Stephen Nelson Avatar answered Oct 17 '22 01:10

Stephen Nelson