lit: Values changed outside of lit-html rendering are not updated from lit-html
Since lit-html stores previously rendered values for dirty-checking, any value changed from outside lit-html will not be overwritten in another render if the value passed to lit-html is the same.
See this live example: https://stackblitz.com/edit/lit-html-rt4n6e
This is actually working as intended, as it’s intended that lit-html maintains control over bound values. But this issue has come up a few times in properties that are affected by user actions:
HTMLInputElement.valueElement.scrollTop
Currently the recommended solution would be to add event listeners which update the bound value so that they’re in sync. That’s non-obvious though, and we should handle this automatically if we can.
One option is to stop storing the previous value in AttributePart, PropertyPart, etc., and instead use the current bound attribute/property value instead as the source of truth.
There are two potential downsides:
- It might be slower, especially for native DOM properties. Crossing DOM bindings just to see if a value should be updated might slow things down.
- Values may be modified by the setter. For instance,
e.className = ['a', 'b']results in a className ofa,b. This would defeat the dirty check and cause it to be set every render.
Another solution is to vend a directive that defers to the underlying property specifically for these cases:
import {live} from 'lit-html/directives/live.js';
// ...
html`<input .value=${live(value)}`>`;
// or
html`<div .scrollTop=${live(top)}`></div>`;
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 11
- Comments: 29 (13 by maintainers)
Commits related to this issue
- Add live() directive Fixes #877 — committed to lit/lit by justinfagnani 4 years ago
- Add live() directive (#1057) * Add live() directive Fixes #877 — committed to lit/lit by justinfagnani 4 years ago
Thanks for this Justin. May I ask… can you ask the documentation guys to actually document it? At the moment there is no sign of it in https://lit-html.polymer-project.org/guide/template-reference and I think it’s a very useful directive in some common cases
On Thu, 16 Jan 2020 at 07:47, Justin Fagnani notifications@github.com wrote:
I am about to hit this problem. @justinfagnani do you have something “official” in the works? It will avoid me wasting time on my own (often half broken) solution…
That work around is correct, and is a somewhat heavy-handed but totally valid approach to getting the desired outcome.
The real problem is that the model (what lit-html thinks is the value of the input) and the reality (the actual state of the input) is not the same. This happens when “a radio button is set to checked outside lit-html” and this change is not correctly synced back into the model. If lit-html thinks the checked property was false and still is false, it won’t bother setting it to false. This is good, because it cuts down on useless operations, but if your checked property changed to true outside the knowledge of lit-html, then it is obviously bad, because the property should be set to false again.
The “real” solution to fixing this problem is by making sure your input state is always synced with what lit-html thinks, but this can be very cumbersome and sometimes hard do correctly. In those cases, a simple solution like the above can be appropriate.
I will try my hand at implementing a
livedirective over the weekend, which is an alternative to thisforcedirective, but in the grand scheme of things I expect the performance difference between these to not be very significant.I think directive way more clearify solution, but less intuitive for beginers.
Anyway, i prefer directive.
This happens with the checked attribute on certain input types as well.