Fork me on GitHub
#clojurescript
<
2021-02-14
>
henrik4211:02:57

Hi, I know of Reagent/React and the way it constructs the DOM. But what if I wanted to express DOM manipulation as data? Could I use zippers for that? Any other idea?

p-himik11:02:57

My first thought was about clojure.data/diff and its result.

p-himik11:02:19

But it may end up being more verbose than the end result.

henrik4212:02:16

The question came up when I realized that DOM event-handlers must be mutators to have any effect. They may use pure functions internally. But in the end they must have some side effects. So I was wondering if one could express this side effect (DOM mutation) as data. So I would trade more verbosity for better testability. Does that make sense?

p-himik12:02:09

It does, although I don't think I've seen such approach implemented anywhere. It sounds like you want to tightly couple any UI events that have to be reflected back in UI with the structure of the UI itself. If that's the case, I'd argue that it's not the best approach. Consider re-frame for example. There, views determine their state based on the data. There's no mutation of the DOM - there are mutations of the data that, in turn, creates potentially different views. The events trigger the data mutations - they don't care about the views at all.

henrik4212:02:27

I agree. Using data in the first place and construct the DOM from there is much nicer than poking into the DOM. But we have a JSF app with JS parts and I'm thinking on how to improve things a little. And part of improvement could be to have testable event callbacks. React & co are not an option at the moment.

dazld12:02:43

In practice, DOM updates trigger all kinds of other stuff inside the browser too - for example reflow when reading or changing attributes - much of the magic in view libraries is, I think, in batching the updates in a performant way.

p-himik12:02:41

Ah, I see. An alternative approach would be to extract any DOM-modifying code in separate functions and then split them into DOM manipulation primitives. This way, you don't have to be able to handle arbitrarily complex DOM manipulations - you just have to handle and compose a bunch of primitives.

henrik4218:02:06

Right, many things that you do to the DOM will trigger a cascade of other things. My focus really is testability of my event handlers at the moment. EDIT: and as a first step I would be satisfied if I could just check that my handler 'does its job'. Of course that does not tell you anything about if the cascade of things that get triggered by that will lead to the correct behavior. I would like to express the mutation as data so that I can compare that against a reference value. A 'diff of DOM' could work but would tie the data to the concete DOM structure. Very fragile. What about something like a clojure-equivalent of XSLT? This would allow for more generic mutations that could 'reach into' the DOM to select those nodes that need mutation.

henrik4218:02:51

@U2FRKM4TW Good idea. That would be a DSL for DOM mutation. Could XSLT be that DSL?

p-himik18:02:36

HTML5 in general is not a valid XML, so I don't think so.

p-himik18:02:02

But even if HTML5 was a proper XML, you still wouldn't be able to use it. Consider a plain <input type="text">. And then you change the value. The layout is not changed at all, the value attribute will not be set. But inputElement.value will be different. XSLT cannot reflect that.

p-himik18:02:52

(I just realized that I was by default assuming you're using HTML5, whereas you could be using XHTML. But the point about value still stands.)

henrik4218:02:08

I'm not targeting HTML or XML. I would like to do somethimg like XSLT to the DOM. In memory. Not a file. And the DOM should be a tree. Isn't it?

p-himik18:02:22

You asked specifically about XSLT, and I believe I have answered that. Regarding "something like XSLT" - no idea. Maybe it's possible, maybe not. Also, an HTML document is only a tree if you don't use any JS. Otherwise, it's easy to link elements together via closures, thus creating loops and turning the tree into a graph.

henrik4222:02:43

Thanks for your thoughts on this. I did some googling and found this: https://clojureverse.org/t/declarative-data-manipulation-or-dsls-in-clojure/4226/10 and https://github.com/HealthSamurai/ironhide https://github.com/redplanetlabs/specter sounds as if it could be a start. Have to think more about what I'm trying to do.

p-himik22:02:47

Honestly, no idea how you gonna use specter in this scenario. :) In short, it's just an arguably nicer way to process deeply nested collections, that's it. It won't help you with arbitrary DOM tree transformations. At least, not more than a regular Clojure code would. I'm not familiar with iconhide at all so cannot really comment.

william11:02:58

Hi, I'd appreciate some input or pointer on how you automatically execute you unit-tests (I use shadow-cljs) - ideally from inside emacs

william15:02:06

solved: I first start shadow-cljs from my emacs instance. Then I visit localhost:9630, and manually activate my testing build. The output of that goes to my emacs repl automatically.