Currently template instances are being cached with strings as a key, which is a great performance optimization, but there are times when this cache needs to be ignored and a full render needs to be done.
An example I'm running into is the case of a web component that has an edit form. This is a fairly typical scenario - i.e., there are a list of items, each with an edit link. When you click edit, the "edit-component" displays. The edit component is bound using lit-html, not extended.
When a user modifies the form contents, this sets the browser's dirty flag, so subsequent calls to render() don't work - because render() just does a setAttribute(), per the html spec, that won't override the value property of an input once the dirty flag has been set.
The effect of this is that when the user clicks "edit" on an item in a list, saves, then clicks "edit" on another item, the contents of the form display the first item.
This particular scenario, I think, is fairly specific to the unique behavior of 'value' attribute v/s property on inputs, but I think it's a common use case to have a form with value bound to an object.
There are a few ways I can think of to solve the problem:
1) I could try deleting and reinstantiating the edit component, but honestly, I'm not sure that would solve the problem because lit caches on strings, so I'd still get a cache hit, right?
2) I can use lit-extended and bind to the property instead of the attribute (but this isn't a great solution in the general case)
3) lit-html could expose an API for deleting a cached item, thus forcing a full rerender. Since the template is cached on a strings key, this might be a bit tricky. Another option might be to add a param to render like 'force' that ignores the cache.
Thanks for the great work on this lib!!
I do think that lit-extended is likely the best option here, because properties have the behavior you want. For what it's worth, I'm strongly considering making lit-extended the default export in the near future.
A force render that skips dirty-checking could make sense in some cases, but in this case it wouldn't help because even a force render would still call setAttribute(). I don't think a force render that actually removes the TemplateInstance would fit well with the library, since you can just empty the container yourself.
Another option is a directive for setting the property, even though you're using plain lit-html. In that case I'd still recommend using lit-extended.
Making lit-extended the default export would be great!
@klebba
I think that division for _lit_ and _lit-extended_ is really awesome. For me it's obvious that exported by default should be core, not extension for it.
If lit-html is used to build web-components, almost always should properties be used over attributes. There are not many times in javascript where you write el.setAttribute('required', '') over doing el.required = true. It's mosly when using SVG where you need to set attributes. I support making the lit-extended the default behavior, as I think it's what is going to get used the most.
I like the division between lit and lit-extended because of the special syntax used in lit-extended. That being said, the bug I encountered was nasty. It took me a long time to figure out what was happening. Add that to the fact that there really isn't an intuitive solution to the problem with vanilla lit, I think we could cause a lot of people pain with this situation. I think the tradeoff of special syntax is worth it, if it's the only way to help the developer community at large avoid the kind of issue I ran into. So +1 from me for making lit-extended the default, and keeping the docs clear about how to get lit-light or whatever if you're doing very simple template rendering.
Hi,
@claytongulick, how did you work around this issue? I have the exact same scenario, having an input field for leaving comments/notes on my "product-page" element. But after leaving a note on the first product's page, the input on the second page shows the text from the previous page. No matter how I try to bind to its value (attribute, property), it doesn't get updated.
@vedtam I ended up just using lit-extended, which fixed the problem. Lit is in a bit of a transitional phase right now with the new syntax being the default for the upcoming release, that explicitly sets properties with .prop in the markup. For now, I'm bound to that version of lit rather than the published npm version.
lit-element uses lit-extended by default
I'm using the latest 'lit-element' which extends 'lit-extended' if I'm not mistaken, and the issue still persists.
What version are u using?
@vedtam I'm using [email protected] and I had to switch from attributes to properties:
<!-- not working with attribute -->
<input type="text" value="${myvalue}" />
<!-- working with property -->
<input type="text" .value="${myvalue}" />
This should be fixed by lit-extended being merged into the main library. Property setting works better for input/value.
Most helpful comment
@klebba
I think that division for _lit_ and _lit-extended_ is really awesome. For me it's obvious that exported by default should be core, not extension for it.