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)
3
  • 1
    I assume in your actual setup, you get proper JSON? Commented Mar 22, 2012 at 11:05
  • So far I think the answer is really: there is no idiomatic way of doing this (yet). Commented Mar 24, 2012 at 23:07
  • Last response was a while ago -- is (str data.o.answer) idiomatic? Commented Dec 27, 2015 at 6:50

5 Answers 5

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

Sign up to request clarification or add additional context in comments.

2 Comments

For the record, it's variadic now. (aget data "o" "answer") would work.
FWIW, David would retract this answer these days, and suggest instead (goog.object/get foo "list"). See more in the answer by Jiacai Liu.
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"

3 Comments

Does indeed work, still seems clunky to me, even with threading macros.
the parens in the threading are redundant (-> data .-o .-answer)
@noisesmith these days I'd prefer to use (.. data -o -answer), as noted by @stephen-nelson - i'll update the answer
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.)

3 Comments

I'm finding that the data is converted into a vector rather than a hash, so actually more co,plicated to extract data from than the default js object
Actually, the converted data seems to vary unpredictably ... obj map or vector
This is like buying the whole grocery store just to get the oranges. A waste of resources.
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]

Comments

2

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

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

See more

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.