Why is input element retaining the value? Data binding is not applying the second time

109 views Asked by At

Using lit element... I have this element called single transaction. From the list of transactions page, I click on single transaction and go to a new page with single transaction.

In the notes input element:

  1. I edit the input and change 'foo' to 'bar'
  2. I do not save
  3. I go back to main page.
  4. I then go back to the same single transaction.

The notes input has the edited value bar. It should have foo since I did not save the value. Why did the bar value persist? It seems when I go back single-transaction element the .singleTransData=${this.singleTransData} data binding would show the original value foo. It's like the data binding logic is not running again and updating the element.

Before input is modified with bar: enter image description here

When input value persists without saving: enter image description here

parent element

      <single-transaction
        data-el="add-catergory"
        .singleTransData=${this.singleTransData}
        id="single-transaction"></single-transaction>

single-transaction element:

  static properties = {                                                
    singleTransData: {                                                 
      type: Object,                                                    
    },                                                                 
    label: {                                                           
      type: String,                                                    
    },                                                                 
  };                                                                   
                                                                                                                                            
  constructor() {                                                      
    super();                                                           
    this.singleTransData = {};                                         
  }                                                                    
                                                                       
  render() {                                                           
                                                                       
    return html`                                                       
          <mwc-icon-button                                             
            @click=${this.#leavePage}                                  
            icon="arrow_back"></mwc-icon-button>                       
                                                                       
          <span class="row">                                           
            <md-outlined-text-field                                    
              label="notes"                                            
              data-key="notes"                                         
              value="${this.singleTransData.notes}"                    
              ></md-outlined-text-field>                               
          </span>                                                      
    `                                                                  
  } 
1

There are 1 answers

1
Justin Fagnani On

If you're keeping the DOM that contains the <single-transaction> connected while you go to the main page, say either by showing the current page with just CSS, or using the cache() directive, then the input, it's current value, and the binding to it are all preserved.

Lit bindings remember their previous value and only update the DOM when the data changes. This means that for elements that change their internal state, Lit won't reset it when you re-render with Lit using the same value as the previously rendered value.

That is, if you render with Lit and value "foo", internally change the value to "bar", then re-render with Lit and value "foo", Lit won't set the property because for all it knows the value is still "foo" and doesn't need to be changed.

This only happens with elements that modify their own internal state (sometimes called "uncontrolled components" in React-land). To help with this Lit has the live() directive: https://lit.dev/docs/templates/directives/#live

live() bypasses Lit's internal binding value storage and always checks against the live value of the property you're bound to.

<md-outlined-text-field> already uses live() to bind to it's internal <input>, and updates it's value property on the input event, so it's value property is always up-to-date. You should be able to add live() to your template to achieve the same:

            <md-outlined-text-field                                    
              label="notes"                                            
              data-key="notes"                                         
              value="${live(this.singleTransData.notes)}"
              ></md-outlined-text-field>