I'm trying to bind a controller variable with lightning-input's value. For instance myVar

So far

Following all examples and documentation of LWC I'm able to do so by using the onchange method and value attribute in this way.


<lightning-input type="number" name="input1" value={myVar} onchange={input1OnChange}></lightning-input> 


//... declaration lines

@track myVar = 0;

   this.myVar = event.target.value;

This works fine in both directions of changes (From the input element or from the js controller). But it is tedious when you have several inputs.

What I was expecting

I was expecting that a @track notation on some controller variable gets updated the value automatically from the input element when it changes.

<lightning-input type="number" name="input1" value={myVal}></lightning-input> 


Why is not LWC framework handling input element > controller variable change automatically? In other words, why binding is not bidirectional? I don't think performance is the answer because the listener is the most costly part and is already implemented.


Based on the feedback received here I found a more generic way to deal with a large number of bindings using this approach:


 <lightning-input name="input1" onchange={genericOnChange} value={input1}></lightning-input> 
    <lightning-input name="input2" onchange={genericOnChange} value={input2}></lightning-input> 


    @track input1 = 0;
    @track input2 = 0;

        this[event.target.name] = event.target.value;
  • In your input you have myVal, in your controller you have myVar, or is it just a typo in your post? – glls May 5 '19 at 18:18
  • typo fixed, good catch – Martin Borthiry May 5 '19 at 18:33
  • this[targetName] works great! Thanks:) – SFDC Oct 23 '19 at 6:20

You can use a single handler to capture the values in all of your inputs.

Here is my favorite approach that has 0 maintenance once you put it in, all you need to know is what "Field" and what "Value" and you can pump an object full of this information, just like a map with key and value.

This uses an object and bracket notation to assign the data to the correct object property.

I've used this many times to keep changes easy, adding fields to HTML and logic to JS without having to touch the handler.

// define your object, it'll look just like an sobject in the end
@track theRecord = {};

    // In 1 line, assign the value to the property
    this.theRecord[event.target.name] = event.target.value;
    console.log(event.target.name + ' now is set to ' + event.target.value);

// example: 
      // event.target.name == 'FirstName'
      // event.target.value == 'Mike'

      // End result: 
        // this.theRecord.FirstName = 'Mike';
        // Dynamically created a new property for theRecord... it'll look like this:
        // this.theRecord = {FirstName: 'Mike'};

    // see the full structure of our object as it grows
    // console.log('theRecord: ' + JSON.stringify(this.theRecord, null, '\t'));


<div>See output like {theRecord.FirstName} {theRecord.MiddleName} {theRecord.LastName}</div>

<lightning-input type="time" name="FirstName" label="First Name"

<lightning-input type="time" name="MiddleName" label="Middle Name"

<lightning-input type="time" name="LastName" label="Last Name"

It is not there but you can avoid by defining 20 handlers.

Don't use multiple event handlers. Just create on the handler and call it on all 20 inputs. I am using this way:

    if( event.target.name == 'tag_name_0' ){
        <Your Var> = event.target.value;
    else if( event.target.name == 'tag_name_1' ){
        <Your Var> = event.target.value;
    else if( event.target.name == 'tag_name_2' ){
        <Your Var>= event.target.checked;
    else if( event.target.name == 'tag_name_3' ){
        <Your Var> = event.target.value;

<lightning-input type="time" name="tag_name_0" label="Label 1"

<lightning-input type="time" name="tag_name_1" label="Label 2"

<lightning-input type="time" name="tag_name_2" label="Label 3"

<lightning-input type="time" name="tag_name_3" label="Label 4"
  • Thank you for your suggestion. It is true that a generic handler could be made – Martin Borthiry May 7 '19 at 7:24
  • Please see the answer with the generic handler that does not need maintenance using just this.theRecord[event.target.name] = event.target.value; – Mike Katulka May 29 '20 at 18:37

In other words, why binding is not bidirectional?

LWC is designed with one way data bind in mind, therefore, it's now a required action on your part to retrieve anything (even out of a base component). Emphasis mine:

The data binding between components for property values is one-way.

To communicate up from a child component to a parent component, send an event.

Which is exactly what salesforce is doing, they are allowing access to a standard event which carries the payload of the value (event.target.value) for you to manually deal with.

  • Thank you for your answer @tsalb, That is exactly my understanding of how it works. But my questions WHY was designed in that way? In a component that involves more than 20 inputs is a mess to have 20 onChange identical handlers. That has no sense for me. – Martin Borthiry May 6 '19 at 8:07
  • @Martin Borthiry that's a question to the LWC team, but IIRC it was due to having more predictable behavior. Two way data binding was a double edged sword and Salesforce must have thought it did more harm than good (across the ecosytem) – tsalb May 6 '19 at 15:29
  • @MartinBorthiry actually, i was playing with attaching events dynamically today. In your specific use case, you would use this.template.querySelectorAll('.my-inputs') and iterate through the collection to dynamically .addEventListener to it. – tsalb May 7 '19 at 0:15
  • Thank you James. That is a good approach indeed. You gave me a good insight. Please take a look at my updated post. – Martin Borthiry May 7 '19 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.