A ClojureScript DOM manipulation, templating and event library.
Add the following dependency to your project.clj
:
[prismatic/dommy "0.1.1"]
DOM nodes are selected using macros, which expand to the correct native dom calls. Because selectors don't wrap returned nodes, there is a distinction between single and multiple selections. A selector can be a keyword, string or vector.
(:use-macros
[dommy.macros :only [sel sel1]])
(sel1 :body) ; => document.body
(sel1 :#header) ; => document.getElementById("header")
(sel1 ".todo") ; => document.getElementsByClassName("todo")[0]
(sel [:#todos :li]) ; => document.querySelectorAll("#todos li")
Inspired by jQuery, but adapted to be functional in order to better fit with ClojureScript core.
(dommy/append! (sel1 :#todos) [:.todo "Eat some cake"])
(doseq [todo (sel :.todo)]
(dommy/add-class! todo :complete))
(map dommy/text (sel :.todo))
Functions that modify take the target dom node as their first argument, and return the same modified node, allowing the use of threading macros to accomplish jQuery-like chaining.
(-> (sel1 :#my-button)
(dommy/remove-attr! :disabled)
(dommy/add-class! :active)
(dommy/set-text! "Click me!"))
(->> (sel :.image)
(filter #(> (dommy/px % :width) 500))
(map #(dommy/add-class! % :big-image)))
Dom manipulation is defined in dommy.core and dommy.attrs.
Templating syntax is based on Hiccup, a great HTML library for Clojure. Instead of returning a string of html, dommy's node
macro returns a DOM node.
(:use-macros [dommy.macros :only [node]])
(node
[:div#id.class1
(for [r (range 2)]
[:span.text (str "word" r)])]) ;; => [object HTMLElement]
;; Styles can be inlined as a map
(node
[:span
{:style
{:color "#aaa"
:text-decoration "line-through"}}])
The deftemplate
macro is useful syntactic sugar for defining a function that returns a DOM node.
(:use-macros [dommy.macros :only [node deftemplate]])
(defn simple-template [cat]
(node [:img {:src cat}]))
(deftemplate simple-template [cat]
[:img {:src cat}])
Thanks to @ibdknox, you can define view logic for custom types by implementing the PElement
protocol:
(defrecord MyModel [data]
dommy.template/PElement
(-elem [this] (node [:p (str "My data " data)])))
(dommy/append! (sel1 :body) (MyModel. "is big"))
One caveat of using the compile-macro is that if you have a compound element (a vector element) and want to have a non-literal map as the attributes (the second element of the vector), then you need to use ^:attrs
meta-data so the compiler knows to process this symbol as a map of attributes in the runtime system. Here's an example:
(node [:a ^:attrs (merge m1 m2)])
Dommy comes with reasonably extensive tests. To run them
first build the test
cljsbuild target, as follows:
$ lein clean
$ lein cljsbuild auto test
Next, open up the HTML file under resources/dommy-tests.html
which will give you a visual representation of all tests. For
all pull requests, please ensure your tests pass (or add test cases) before submitting.
Copyright (C) 2013 Prismatic
Distributed under the Eclipse Public License, the same as Clojure.