Yeah, so the problem is that when data dataflows, the formInput function cell reevaluates (take note of the grey bar flickering). This in turn causes the UI cells to reevaluate too. Thus, its like deleting the whole UI and recreating it. So the users slider state is lost (including the mouse handler).
For smooth UI, you do not want dataflow to recreate the whole UI from scratch, so references to the variable data should be avoided. Note that ‘viewof data’ is a different variable which is not updated often, so Inputs.bind(ui, viewof data) is ok, and this lets you sync data without a dataflow dependancy. See Synchronized Inputs / Observable / Observable
bind is calling addEventListener() to passed in args, so it is event driven like dataflow still. Note the function formInput no longer reevaluates, because it no longer has a data dependancy on “data”. Instead it is dependant on “viewof data” which is setup only once.
aah cool. Yeah, “viewof data” is the outer presentation (often DOM) variable. It’s property “value” is the inner data variable. Because a view holds a data variable, I sometimes mentally model views as pointers (but they also do other things so that description is not sufficient).
There is a Composite value that’s updated any time any of the inputs update. It’s powered by manually creating oninput functions on each input that will drive the composite value:
setData = (a) => {
a.map(div => div.oninput = () => set(viewof data, a)) //when each control updates, update `data`
set(viewof data, a) //update `data`
}
This is the big part that you helped me solve above.
The inputs are all bound together
I can have as many views of the controls as I want.
I can add, remove, etc. the controls pretty easily.
This feels like some serious duct tape but it works …
One thing I have noticed is that you have separated out your “controls” vs your “data” as two distinct views, but this distinction is already part of the viewof machinery. The outer viewof variable (the view) should be a DOM node and is a UI. The inner value should be a pure data objects like a number.
So “viewof data” is the UI. and “data” is the value if we are being idiomatic.
When I want to instantiate multiple UIs I switch to a builder pattern, which by convention I always pass in an options arg (so I can add features without breaking old version).
If we want one view linked to another you can use Inputs.bind. I put this in the options but you could do it outside too.
lol. Ooops. Yeah, that kind of makes sense as its replacing the whole array every bind which implies replacing the whole DOM every time. This should be work
Tom, Also I found a bug in my own example when removing data — then clicking “add item” doesn’t refresh the inputs cell, so it won’t show the new input(s).
The reason for both data and controls is just that data is a copy of controls so that I can update the inputsForm when an item is added. The inputsForm needs to be bound to something that’s not controls or it ends up in the render loop / replacing DOM problem.
Looking forward to seeing your version or if you have ideas for how to fix the reactivity loop in mine without needing the duplicate of the controls in data. Thank you.