Question

I'm trying to do something simple with Clojure Enlive lib: I want the top menu of my page to be different based on language selected by the user (English or Japanese). I can't find how to implement this basic feature.

I have a "template/header.html" template with 2 sections (one per language):

<div class="header en-US">...</div>
<div class="header ja-JP">...</div>

I created 2 corresponding snippets in my templating code:

(:require [net.cgrand.enlive-html :as html])
...
(html/defsnippet header-ja-JP "templates/header.html" [:div.header.ja-JP] [])
(html/defsnippet header-en-US "templates/header.html" [:div.header.en-US] [])

Now when I load my main template (index.html) I want to populate my header menu code into my nav tag.

Below, the argument 'lang' value is either "en-US" or "ja-JP":

(defn process-template
  [lang]
  (let [header-selector  (str “header-“ lang)
        header-content   (@(resolve (symbol header-selector)))]
    (apply str
           (html/emit*
            (html/at
             (html/html-resource "templates/index.html")
             [:nav] (html/content (header-content)))))))

It throws a java.lang.NullPointerException

If I replace the last line by

[:nav] (html/content (header-ja-JP)))))))

or

[:nav] (html/content (header-en-US)))))))

it works fine (so the snippets work), but I've tried lots of different syntaxes and can't make the dynamic header work based on language.

The above code (let part) seems ok if I execute it manually in REPL, the header-content is JSON object containing the correct content so I don't understand why I get a NullPointerException.

Ideally I think I should have only one snippet taking the language as argument and returning the corresponding HTML section, but didn't manage to do that either.

I'm very new at Clojure so I'm probably missing something obvious here; if someone could point me to what's wrong in the code above or another way to make this work that will be awesome.

Thanks, Olivier

Was it helpful?

Solution

If we want to do it differently as cgrand suggests, there are many, many ways to accomplish this. I have a hard time imagining how he'd do it with maps, but I'd do it this way:

(defn process-template [lang]
  (html/select (html/html-snippet
                 "<html>
                    <head></head>
                    <body>
                      <nav>
                        <div class=\"en\"></div>
                        <div class=\"jp\"></div>
                      </nav>
                    </body>
                  </html>") 
        [(keyword (str "div." lang))]))

(apply str (html/emit* (process-template "en")))
=> "<div class=\"en\"></div>"

Of course read it from file instead of HTML in a string. The function plucks out the matching HTML node according to a selector.

OTHER TIPS

Your (@(resolve (symbol header-selector))) returns a value. (resolve (symbol header-selector)) returns a function.

[:nav] (html/content (header-content))))))) calls header-content as a function.

Replace (@(resolve (symbol header-selector))) with (resolve (symbol header-selector)).

I'm fuzzy on what html/at and html/html-resource do so if other problems crop up you might need to cram in clojure.java.io/file in there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top