Petrus Theron
Petrus Theron

Reputation: 28807

How to conditionally unroll Hiccup data structures in Clojure

How to elegantly render a conditonal list of menu items in Clojure's Hiccup-like data structures? My templating function ends up littered with calls to into and does not read naturally.

Desired result:

[:div.menu
  [:div.item "Home"]
  [:div.item "Private"]
  [:div.item "Private"]
  [:div.item "Public"]

If I put the private items in an if, I still need to unroll the returned vector, or deal with nil, so this doesn't work:

[:div.menu
  [:div.item "Home"]
  (if authenticated?
    [[:div.item "Private"]
     [:div.item "Private"]])
  [:div.item "Public"]]

I found I can use (into [:div.menu] ...) and pass in a list of items, but it's unwieldy and doesn't read naturally. I ended up with this expression:

(-> [:div.menu
      [:div.item "Home"]]
  (into (if (auth/authenticated?)
      [[:div.item "Private"]
       [:div.item "Private"]]
  (into [[:div.item "Public"]]))

Is there a better way?

Upvotes: 3

Views: 367

Answers (1)

Petrus Theron
Petrus Theron

Reputation: 28807

Turns out Hiccup treats lists differently from vectors, so you can return a () instead of a [] and have it unroll correctly:

[:div.menu
  [:div.item "Home"]
    (if authenticated?
      (list
        [:div.item "Private"]
        [:div.item "Private"]))
  [:div.item "Public"]]

Upvotes: 3

Related Questions