Hi, I made the following notebook as a reduction of something I am not able to do.
Based on Synchronized Inputs / Observable / Observable I was expecting to be able to set the value of synchronized inputs via a non-DOM input input.
In my example is either as a timeout after creation or via an explicit button click. Neither of those works.
Would someone know what I might be missing?
Thanks in advance!
1 Like
EDIT: you need viewof infront of the non-DOM too to do what you intend
In your version the bind works, in that the nonDOM object is updated, but the notebook UI is kinda broke because that doesnāt have the hint that the UI and value have been seperated (viewof)
Other gotcha note: generally you want bubbles: true
input.dispatchEvent(new Event("input", {bubbles:true}));
1 Like
Thanks @tomlarkworthy for the input. Unfortunately I donāt see that does change make any difference . Applying those changes (and even after adding a viewof
in () => set(viewof nonDom, ...)]
) I see no updates in the main input after attempting to send updates via de nonDom input.
I updated a newer version with a couple of more callbacks to check. So itās not an issue of doing the update inside a setTimeout
since that works on dom inputs.
I am attaching a gif recording to show how the input an name are unsync on my end.
Thanks again for your time!
1 Like
oh I see what you mean. When nonDom is set, the appearance of the text updates but the underlying value does not change. maybe an event is raised but we canāt tell.
Could be an issue with bind, or the DOM input component somehow masking it. I will come back to this later coz I am AFK ATM
1 Like
I believe this is a bug in Observableās Inspector, as dependent cells are still updated properly. For viewof cells the Inspector normally just passes through the viewof
Variable value (the Element
). But for EventTarget
it constructs its own representation, which it then fails to update. You can see the representation update if you expand/collapse it.
/cc @mbostock
2 Likes
Itās not really a bug; itās just a limitation of how the inspector works. The inspector doesnāt do deep observation of objects because that would be expensive (e.g., everything would need to be wrapped with a Proxy). Setting the value of a view doesnāt change the view (foo
updates, but viewof foo
is unchanged), so the inspector doesnāt run.
1 Like
@bcardiff Unfortunately the workaround is rather ugly, as it involves creating your own Inspector instance and passing in the cell name manually:
inspect = {
const {Inspector} = await require("@observablehq/inspector");
return (target, name) => {
if(target instanceof Element) return target;
if(!target instanceof EventTarget) return new Inspector(html`<div>`).fulfilled(target, name);
const el = Object.defineProperty(html`<div>`, "value", {
get: () => target.value,
set: v => target.value = v,
});
const i = new Inspector(el);
i.fulfilled(target, name);
el.addEventListener("input", () => i.fulfilled(target, name));
return el;
}
}
function delayedInput(value, name) {
const res = inspect(Inputs.input("initial"), name);
window.setTimeout(() => set(res, "value set in setTimeout"), 2000);
return res
}
viewof nonDom = delayedInput("value set by the timeout", "nonDom")
1 Like
It seems I am attempting something out the expected use case. :-S
I understand if this out of scope. But from the explanation @mootari is given I thought:
Maybe I can use a DOM Input instead of a non-DOM and that might work.
function delayedInput(value) {
//const res = Inputs.input("initial")
const res = Inputs.text({value: "initial"}) // now is a dom Input
window.setTimeout(() => set(res, "value set in setTimeout"), 2000);
return res
}
But it doesnātā¦ after the timeout happens I see the expected value in both inputs, but on other cells that references name
the value is not updated.
name + "."
will still show "initial."
- even if I reevaluate or if I create another cell with a similar formula
A cell with (viewof name).value
will show the right value only after a manual re-evaluation.
I republish the notebook just in case with this cases.
I will take a step back, maybe what I am trying to do can be approached in a different way. I was trying to have some library that will play nice with Observableās Inputs and extend them. I will see If I can do it without Inputs.bind
.
Thanks!
1 Like
Perhaps you could elaborate what exactly youāre trying to do?
1 Like
Sure thing
I was trying to define some helpers to store inputs in local-storage with an option to store them encrypted.
Now Iām not sure why I went the route of Inputs.bind
instead of setting / listening to the main input directly. That works like a charm .
Before, I was trying to use the non-Dom input in a closured, manipulate those and let Inputs.bind
sync the values.
It puzzles me that there are some non obvious constraints from the user perspective regarding dom inputs and non-dom inputs on Inputs.bind
ā¦ but if this is the first time is must not be that common.
Thanks!
The underlying issue is not pure aesthetic. The underlying value is not updated.
(viewof name).value DOES UPDATE (correct)
(name) DOES NOT UPDATE (incorrect), rerunning the cell does not help
calling (viewof name).dispatchEvent(new Event(āinputā)) DOES fixes it. So the issue is a missing event.
I see this as a composability wart with Input bind. The input events are not raised at the source so you cannot chain binds in both directions. A clearer repro:
bind is not truly symmetrical in behaviour with raising events
(see inputs/bind.js at main Ā· observablehq/inputs Ā· GitHub)
Personally I donāt see this as a problem, two way binding is not usually needed, there is usually a clear primary, so you can reverse the direction of the bind to remove the problem.
You may want to reread both mine and Mikeās explanation of the underlying issue.
yeah thats the issue here
as dependent cells are still updated properly.
was not correct. Dependant cells were not updating properly because the bind is in the wrong direction.
viewof name = Inputs.bind(Inputs.text({label: āNameā}), viewof nonDom)
Sets the text as the target and nonDom as the source. So sending events to nonDom breaks dataflow downstream of the text().
bind(target, source, ā¦)
"When the target emits a type-appropriate event, the target ās type-appropriate value will be applied to the source and a type-appropriate event will be dispatched on the source ; when the source emits a type-appropriate event, the source ās type-appropriate value will be applied to the target , but no event will be dispatched , avoiding an infinite loop.
So in this use case events sent to nonDom will not be mirrored on the ānameā text view.
I usually read docs in observablehq and not on github. On Synchronized Inputs / Observable / Observable I think there is no mention of the non-symmetry behaviour that is causing the underlying issue.
I think the issue can be summarised for users as: Do not capture in a name the result of the Inputs.bind
. Doing so will might lead to unexpected results.
Tweaking the last example of Synchronized Inputs / Observable / Observable, by adding a viewof y =
we can see that
Thanks again to everybody , I will keep enjoying ObservableHQ
2 Likes