17
votes

Anyone have any docs for idiomatic clojurescript for access a javascript object (returned as json, essentially a hash)?

I have a JSON object returned via an AJAX request:

{
  list: [1,2,3,4,5],
  blah: "vtha",
  o: { answer: 42 }
}

How do I access these fields using clojurescript?

I can do:

(.-list data)

But how does this work when I have nested values and objects?

(.-answer (.-o data))

The above seems to be quite clumsy, especially given the nice js syntax of: data.o.answer.

What is the idiomatic way of accessing json objects with clojurescript?

Note:

I realised that I can actually refer to elements using JS syntax, which is quite handy actually. So the following will work correctly:

(str data.o.answer)
5
I assume in your actual setup, you get proper JSON? - Felix Kling
So far I think the answer is really: there is no idiomatic way of doing this (yet). - Toby Hede
Last response was a while ago -- is (str data.o.answer) idiomatic? - cnp

5 Answers

17
votes

You probably want aget:

(aget foo "list")

aget isn't variadic yet, but hopefully will be soon it's variadic now. (aget data "o" "answer") would work

11
votes

Firstly, your proposed syntax for nested access does work:

ClojureScript:cljs.user> (def data 
    (JSON/parse "{\"list\": \"[1,2,3,4,5]\", \"blah\": \"vtha\", \"o\": {\"answer\": \"42\"}}"))
#<[object Object]>
ClojureScript:cljs.user> (.-answer (.-o data))
"42"

You can use the threading macros...

ClojureScript:cljs.user> (-> data (.-o) (.-answer))
"42"

Or .. notation

ClojureScript:cljs.user> (.. data -o -answer)
"42"
6
votes

If you're dealing with any amount of data, I'd convert the JSON into clojure data structures and then use the usual idioms:

(let [my-json (js* "{
                     list: [1,2,3,4,5],
                     blah: \"vtha\",
                     o: { answer: 42 }
                   }")
      converted (js->clj my-json)]

  (get-in converted ["list" 3]) ;; => 4
  (-> converted "o" "answer") ;;=> 42
)

(Note: don't use js* if you can help it; it's not idiomatic and might go away in future versions of ClojureScript.)

2
votes

Clojurescript has a .. operator that is useful for chained javascript calls:

(.. data -o -answer) => data.o.answer => 42
(aget (.. data -list) 1) => data.list[1] => 2

You can use most list operators on arrays too, e.g.

(into [] (.. data -list)) ; vector [1 2 3 4]
2
votes

Forget about aget, it's mainly designed for array (array get). Use

  • goog.object/get
  • goog.object/set

See more