DOM Clojurescript Interface

Is there a Clojurescript library that makes the DOM look like a Clojure data structure? I found several libraries, such as Enfocus, that perform certain kinds of DOM manipulations, but I want to be able to handle the DOM as follows:

(get dom id) - returns element called id in dom (get dom id create-fn) - return element if exists, otherwise creates it (update-in dom [:body this that] update-fn) - set attribute on a DOM element (assoc parent-element id child-element) - associate child element with parent (conj parent child) - append child element to parent element 

etc.

+6
source share
1 answer

Clojure data structures are all persistent, but in your example it seems like you want a side effect (i.e. push the DOM in place to change it).

This is a rather procedural / imperative approach, so it might be worthwhile to step back and reformulate the problem in a more functional style. My personal philosophy is to consider “representations as data” and model it with Clojure's persistent data structures until the last minute I need to visualize.

Do you know hiccup? The idea is to represent HTML or SVG DOM using simple vectors and maps:

 [:div {:with "attribute"} "and" [:span "children"]] 

which you can build by compiling simple old Clojure functions. In Clojure, you can display this in HTML (using the original Hiccup library), but there are at least two ClojureScript libraries that directly convert to (potentially existing) DOM structures. Crate is a close port of Hiccup and Singult has some additional semantics such as D3.js-based data binding (Singult is actually written in CoffeeScript, so it can be used with simple JavaScript and faster than Crate).

My C2 library builds data binding semantics on top of Singult to keep the DOM in sync with the underlying data. Consider this template for a TODO list:

 (bind! "#main" [:section#main {:style {:display (when (zero? (core/todo-count)) "none")}} [:input#toggle-all {:type "checkbox" :properties {:checked (every? :completed? @core/!todos)}}] [:label {:for "toggle-all"} "Mark all as complete"] [:ul#todo-list (unify (case @core/!filter :active (remove :completed? @core/!todos) :completed (filter :completed? @core/!todos) ;;default to showing all events @core/!todos) todo*)]]) 

(taken from the implementation of C2 TodoMVC ). Things like checking the check-all checkbox are done directly from the underlying data (stored in the atom). Whenever this data changes, the template will be re-launched, and dom will automatically update.

The main idea is to build mappings in the forward direction from your application data to Hiccup data structures, and then let the library take care of DOM synchronization (add / remove children, attributes, etc.). If you don’t need to worry about the state of the DOM (is it added, do I need to switch some class?), Then there are many random difficulties.

+4
source

Source: https://habr.com/ru/post/919475/


All Articles