3

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?

Petrus Theron
  • 27,855
  • 36
  • 153
  • 287

1 Answers1

3

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"]]
Petrus Theron
  • 27,855
  • 36
  • 153
  • 287
  • The downside with this approach is that if you are using Reagent or a React-based library, you will get unique key warnings. – Petrus Theron Jul 07 '16 at 15:42