I'm relatively new to Clojure and Compojure web development. The first issue that I've noticed in the toy example that I'm building is that of HTML templating. I'd like to have support for something like partials in Rails, or the templating framework that Django uses.
Currently I have:
(defn index-page []
(html5
[:head
[:title "Home | Compojure Docs"]
(include-css "/css/bootstrap.min.css")
(include-css "/css/bootstrap-responsive.min.css")]
[:body
[:div {:class "container-fluid"}
[:div {:class "row-fluid"}
[:div {:class "span2 menu"}]
[:div {:class "span10 content"}
[:h1 "Compojure Docs"]
[:ul
[:li
[:a {:href "/getting-started"} "Getting Started"]]
[:li
[:a {:href "/routes-in-detail"} "Routes in Detail"]]
[:li
[:a {:href "/destructuring-syntax"} "Destructuring Syntax"]]
[:li
[:a {:href "/nesting-routes"} "Nesting Routes"]]
[:li
[:a {:href "/api-documentation"} "API Documentation"]]
[:li
[:a {:href "/paas-platforms"} "PaaS Platforms"]]
[:li
[:a {:href "/example-project"} "Example Project"]]
[:li
[:a {:href "/example-project-on-cloudbees"} "Example Project on CloudBees"]]
[:li
[:a {:href "/interactive-development-with-ring"} "Interactive Development with Ring"]]
[:li
[:a {:href "/emacs-indentation"} "Emacs Indentation"]]
[:li
[:a {:href "/sessions"} "Sessions"]]
[:li
[:a {:href "/common-problems"} "Common Problems"]]]
(include-js "/js/jquery-1.9.1.min.js")
(include-js "/js/bootstrap.min.js")]]]]))
(defn routes-in-detail []
(html5
[:head
[:title "Routes in Detail | Compojure Docs"]
(include-css "/css/style.css")]
[:body
[:h1 "Routes in Detail"]]))
Is there a good way for me not to repeat code? I'd like the stuff in the HEAD tag to be in it's own template file or function, and then be able to include it as I go. For instance, I'd like to include it in the 'routes-in-detail' function. I've looked at Enlive, but I'm not sure how to use that with Hiccup. Any thoughts on best practices here would be appreciated.
You can pull parts of the markup out into separate vars:
(def head
[:head
[:title "Home | Compojure Docs"]
(include-css "/css/bootstrap.min.css")
... ])
(defn routes-in-detail []
(html5
head
[:body
... ]))
If you need your snippet/partial to take parameters, you can make it into a function instead, for example:
(defn head [title]
[:head
[:title title]
(include-css "/css/bootstrap.min.css")
... ])
(defn routes-in-detail []
(html5
(head "Routes in detail")
... ))
Sometimes you'll want your "snippet" to consist of multiple top-level elements rather than a single one. In that case you can wrap them in a list - hiccup will expand it inline:
(defn head-contents [title]
(list [:title title]
(include-css "/css/bootstrap.min.css")
... )))
(defn routes-in-detail []
(html5
[:head (head-contents "Routes in detail")]
[:body ... ]))
Once you realize the fact that hiccup markup is made out of plain clojure data structures, you'll find that manipulating/building it with functions is easy and flexible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With