18

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)
Toby Hede
  • 36,755
  • 28
  • 133
  • 162

5 Answers5

17

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

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
dnolen
  • 18,496
  • 4
  • 62
  • 71
11

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"
sw1nn
  • 7,278
  • 1
  • 26
  • 36
6

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.)

Kevin L.
  • 1,663
  • 1
  • 16
  • 21
2

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]
Stephen Nelson
  • 939
  • 1
  • 7
  • 22
2

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

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

See more

Jiacai Liu
  • 2,623
  • 2
  • 22
  • 42