lit-elementlitlit-html

lit-element v2 clearing text fields with null properties


I have lit-element based forms that are reused for editing entities. As an example consider a name form with the following fields

<mwc-textfield id="first-name" label="First name" value="${this.firstName ?? ''}"></mwc-textfield>
<mwc-textfield id="middle-name" label="Middle name" value="${this.middleName ?? ''}"></mwc-textfield>
<mwc-textfield id="last-name" label="Last name" value="${this.lastName ?? ''}"></mwc-textfield>

The user selects an entity from some list and I fill the properties firstName, middleName, lastName with the corresponding values. The user then may edit the values and press a save button which reads the values of the text fields with something like

this.firstName = this.shadowRoot.getElementById("first-name").value;

and writes them back to the database. This all works well except for one case: when the user edited the fields but then decides to not save the changes and instead load another entity, the data binding seems to be somehow broken for empty properties.

So, f.e. assume the user selected 'Fred Krueger' (firstName=Fred, middleName=null, lastName=Krueger), then typed a middle name 'Jacob' into the field but then decides to not save it and load 'Sarah Mueller' instead. Since her middle name is null, the text field should be cleared. What happens instead is that 'Jacob' remains in the field!

It seems as if a null value will not clear a text field that was edited by the user and not synchronized to the bound property. Note that properties that are not null do always update the fields!

The problem can be resolved by adding a change and keyup handler to each and every textfield in my form to synchronize the corresponding properties.

Question: Is this really the only way to do it? Why does a property with value null not update the field when it has been edited before?

(Edit: changing the binding from value to .value does not fix this!)


Solution

  • This is due to the value property on the DOM being changed by the user input and Lit can't tell the DOM element needs to change. As you've noticed, using an event listener to keep the DOM value and Lit property always in sync is one way to avoid this, and this is often preferable since the Lit components will always have the latest value without needing to look it up from the DOM node.

    Alternatively, using the live directive can force Lit to check against the current live value on the DOM node and properly update it.

    import {live} from 'lit/directives/live.js';
    
    <mwc-textfield id="first-name" label="First name" value="${live(this.firstName ?? '')}"></mwc-textfield>
    <mwc-textfield id="middle-name" label="Middle name" value="${live(this.middleName ?? '')}"></mwc-textfield>
    <mwc-textfield id="last-name" label="Last name" value="${live(this.lastName ?? '')}"></mwc-textfield>