Posts Web Noir plus enlive template
Post
Cancel

Web Noir plus enlive template

Hi again! Long time without writing here. But for a good reason.

One of the most promising web frameworks for clojure is noir. It is actually an abstraction on top of ring and Compojure, both successful clojure products.

By default, noir comes with the excellent hiccup, which allows one write html in clojure like this:

    (use 'hiccup.core)
    (def name "Nacho")
    (html [:span {:id "dog"} name])

    ;; produces:
    ;;"<span id=\"dog\">Nacho</span>"

It doesn’t look designer friendly, right? I would still use hiccup for admin pages or small chunks of html strictly generated by clojure code with a good css to help presenting it.

Enters enlive. I’ve already used enlive before, without understanding it that much, I would say. It’s been almost two years since that post. And what makes me happy with enlive is the possibility to be closer to Scala’s web framework Lift. That is, put some attention on the view with actually working with actions. So, combine this:

    <form  method="post" id="login_form">
        <div id="errors">
            <span class="error"/>
        </div>
        <label for="username">Username</label>
        <input type="text" id="username" name="username"/>
        <label for="password">Password</label>
        <input type="text" id="password" name="password"/>
        <input type="submit" value="Login"/>
     </form>

With a snippet from enlive:

(defn show-errors [msgs]
	(h/clone-for [i msgs]
		[:span.error]
		(h/content i)))

(h/defsnippet _login "mayapp/views/_login.html"  [:#login_form]
	[username password & [errors]]

	;;find sa div with ir='errors'
	[:div#errors]
	(show-errors errors)

	;;finds an input with id ='username' and replaces
	;;its value attribute by username
	[:input#username]
	(h/set-attr :value username)

	;;the same for password
	[:input#password]
	(h/set-attr :value password))

And you have the html output that can be referenced this way:

(defpage "/login" {:as login}
    (_login (:username login)
		(:password login)
		(:error login)))))

;;handling the form submit
(defpage [:post "/login"] {:as login}
	(if (valid? login)
		(format "Yeah!! Welcome %s" (:username login))
		(render "/login" (assoc login :error (v/get-errors)))))

We still have sort of action base framework but with good attention to the view. Not the show-errors function, that can be reused every where with a :div#errors > :span.error. It will repeat the span for every error in msgs.

The error messages may be produce by noir.validation package. In the POST route you can see the snippet being activated with the [errors] argument in case of any errors.

Snippets should be natural for you, and can be used in situations where you define parts of an html, you you have a bigger html resource grouping many parts that cane be a snippet. That is why you passes a selector to defsnipet right after the resource name. That is, transformations will start from this point.

The other option is the deftemplate, it works similar to defsnippet, but doesn’t take any selector as an argument, because it process the entire resource.

A great usage of enlive you can find at Facebook/Heroku sample app – Clojure.

And to help you starting with noir plus enlive, I’ve created a template project using lein-newnew, a way to pack a project as a template, so anyone can reuse it. Please refer to https://clojars.org/clj-enlive-template and the clj-enlive-template source code. Just:

lein plugin install clj-enlive-template 0.0.1
lein new clj-enlive-template myproj
cd myproj
lein run

And start having fun with enlive and noir. This project template may be evolved to have korma or any persistence framework.

This post is licensed under CC BY 4.0 by the author.