hoplon

2023-05-21T08:45:25.407329Z

Hello! I have a (hopefully) small question. When I do this:

(def ctext (cell "Hello!"))

(defn hello []
  (h/div
   ctext
   (h/input {:input #(reset! ctext (-> % .-target .-value))})))
On each char I type in input the input lose focus, why is that? (it seems to rerender for some reason)

2023-05-21T13:27:51.647449Z

This solves the issue:

(h/div
   (h/text ctext)
   (h/input {:input #(reset! ctext (-> % .-target .-value))}))
Look like something related to the rerender of div with direct text that causes the rerender of input

2023-05-21T16:14:38.266679Z

What is the reason h/text has to be a macro?

2023-05-21T22:58:12.787979Z

it doesn't have to be, but h/text supports interpolation

2023-05-22T16:49:15.999839Z

looked into this a little more, i think the relevant code is here: https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.cljs#L299-L300 in your first example, ctext is a cell and goes down the first, (`cell? child)` path. in that case, when the value of child changes, the kids cell<vector> associates element at i (size of kids vector at append time) with the ctext cell's new value in the second example, (h/text ctext) evaluates to a DOM textNode and not a cell: https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.clj#L229-L230 in the second example, the DOM textNode is "static" in the sense that its contents can change internally over time, but as far as the kids cell<vector> it's contained in, it never changes. its value is mutated independently by the cell created in h/text so, back in -append-child!, the non-cell gets appended via (swap! kids assoc i child) zooming out, this touches on some of the design implications of a relationship between data model and DOM in a "retained mode" graphics model. and also the stange algebra of cell/non-cell composition that emerges

2023-05-22T16:50:28.908399Z

finally, i think the first example loses focus because changing ctext modifies the div's kids, and the children get removed and re-attached whenever the ctext cell changes

2023-05-22T16:51:01.039099Z

anyway, hope that all makes some kind of sense, happy to elaborate in any direction in case not

2023-05-21T12:49:45.642639Z

Another question: what is the difference?:

(cell= (str "Hello, " (cell "John")))

(let [a (cell "John")]
    (cell= (str "Hello, " a)))

((formula str) "Hello, " (cell "John"))
the 1st example returns "Hello, [object Object]" the 2nd & 3rd return "Hello, John"

2023-05-21T23:01:43.377989Z

in the first example a cell is created inside a formula and the enclosing cell= is not generating code to derefence the cell before passing to str

2023-05-21T23:03:12.879869Z

i think it's because cell= wraps free variable names with maybe-dereference magic, but arbitrary expressions (`(cell "Jon")` are not

2023-05-21T23:15:10.303669Z

note also that example 2 is representative by far the most common usage, naming a cell outside of a cell= so you can manipulate it

2023-05-23T08:12:01.360349Z

but how would you break c:

(def m {:a (cell 1)
        :b (cell 2)})

(def c (+ (m :a) (m :b)))

(cell= c)
into its operation and operands? the are "applied away". And if its a more complex expression it will be even harder, this is basically what cell= does.

2023-05-23T12:58:27.294879Z

(def m {:a (cell 1)
        :b (cell 2)})

(def c (formula +))

(def result (c (:a m) (:b m)))

(cell= (js/console.log {:result result}))

2023-05-23T12:59:59.604409Z

I think this is nearer what you want. Not sure if near enough.

2023-05-23T17:05:08.460629Z

note also that when dealing with structured updates, lenses can be useful

2023-05-22T09:25:48.835839Z

if I have the following use case:

(def m {:a (cell 1)
        :b (cell 2)})

(cell= (+ (m :a) (m :b)))
where I want to bundle some cells in a structure, and compute over them. please note I'm already aware of the option of let:
(let [a (m :a)
      b (m :b)]
  (cell= (+ a b)))
The catch here is that I also get the computation as a variable and I can't break the computation and extract the cells out, think of something like this:
(def m {:a (cell 1)
        :b (cell 2)})

(def c (+ (m :a) (m :b)))

(cell= c)
Is there any solution that you can recommend?

2023-05-22T11:41:30.296179Z

You could have a bigger cell if that is not a problem in you use case:

(def m (cell {:a 1
              :b 2})

(cell= (+ (m :a) (m :b)))

2023-05-22T11:42:40.967269Z

But I lose granularity, correct?

2023-05-22T11:46:12.880209Z

You mean you will have fewer cells that will trigger bigger updates on formula cells? This is correct but in my experience not a practical problem. I'm not sure about the problem that you are trying to solve to offer other options of how to do it.

2023-05-22T11:53:50.882649Z

The problem I'm trying to solve is quite complex and boil down to having cells in a structure and being able to create reactive computations based on them without explicitly declare them (the cells).

2023-05-22T12:05:30.191479Z

I think formula could work in that situation, the 3rd option in your initial message in this thread.