Because most of the LWCs you will create will contain other nested LWCs, it is important to understand how to use data binding to allow the components to communicate with each other.

We can summarise this saying that, while in aura data binding was bidirectional, in LWC is unidirectional. This means, for sending information from a parent to a child LWC, we use properties. While child components pass data up by firing events.

Let’s use the following example:

This LWC will render 2 lightning-input contained into a lightning-card.

<template>
    <lightning-card title="data Binding Example">
        <div class="slds-p-around_medium lgc-bg">
            <lightning-input
                type="text"
                name="input1"
                label="Change this text"
                value={textValue}
            </lightning-input>
        </div>
        <div class="slds-p-around_medium lgc-bg">
            <lightning-formatted-text value={textValue}></lightning-formatted-text>
        </div>
    </lightning-card>
</template>
import { LightningElement, track } from 'lwc';
 
export default class DataBindingExample extends LightningElement {
    @track textValue = 'testing data binding';
}

If we analyse the code and the previous image, we can find the following.

In the JS file, in our custom LWC (in green), we are declaring a property, textValue. This property is decorated with @track and we are assigning a value, testing data binding, to it.

@track textValue = 'testing data binding';

At the same time, in the HTML file, we are using the property textValue to set the value attribute shown in the lightning-input.

<lightning-input
    type="text"
    name="input1"
    label="Change this text"
    value={textValue}
</lightning-input>

 

We can’t see the implementation of the lightning-input component, but we can imagine it. Bear in mind that base LWC, like the lightning-input, the lightning-spinner, the lightning-record-view-form, etc. are LWC just like yours. And so, their attributes, value, type, label… Are properties defined internally using the @api decorator. 

In other words, what we are doing, is to assign our value stored in property textValue to an @api property in the lightning-input called value;

Let’s have a look at how to propagate down values from a custom LWC to a child custom LWC. As described before, we just need a property in the child component decorated with @api. Which value will be set in the parent LWC.

As we have already a parent LWC we will need to create a new LWC and embed it in our previous LWC.

<template>
    <div>{textreceived}</div>
</template>
import { LightningElement, api } from 'lwc';
 
export default class ChildLWC extends LightningElement {
    @api textreceived;
}

The property created for holding the value set from the parent LWC is textreceived. As you see, this property is decorated with @api and contained in a div in the LWC HTML. That’s it, we will not need to add any extra logic in this LWC.

It is time now to embed our brand new LWC into our previous LWC.

<template>
    <lightning-card title="data Binding Example"> 
        <div class="slds-p-around_medium lgc-bg">
            <lightning-input
                type="text"
                name="input1"
                label="Change this text"
                value={textValue}
            </lightning-input> 
        </div>
        <div class="slds-p-around_medium lgc-bg">
            <lightning-formatted-text value={textValue}></lightning-formatted-text>
        </div>
        <div class="slds-p-around_medium lgc-bg">
            <c-child-L-W-C
                textreceived="this text is being propagated down" >
            </c-child-L-W-C>
        </div>
    </lightning-card>
</template>

Notice that our @api property textreceived is being used just like the property value, label or onchange in the lightning-input. And so, the string “this text is being…” is sent down to the child component trough textreceived.

And as we said before, data binding in LWC is unidirectional. This is, the value of a property will propagate down, from parent to child, but never up, from child to parent. The way to communicate from child to parent needs to be done in a different way, using events. The child component will fire an event, that the parent component will listen to.

This is important to understand because a common mistake is to assume that the property we are using to set the initial value to the lightning-input (defined in the parent), will also receive data inserted by the user. Data inserted by the user comes from a deeper or child level in our case. And so, it will fire an event we will need to listen to.  

In this case, the property to use in the lightning-input is onchange.

<template>
    <lightning-card title="data Binding Example">
        <div class="slds-p-around_medium lgc-bg">
            <lightning-input
                type="text"
                name="input1"
                label="Change this text"
                value={textValue}
                onchange={handleTextChange}>
            </lightning-input>
        </div>
        <div class="slds-p-around_medium lgc-bg">
            <lightning-formatted-text value={textValue}></lightning-formatted-text>
        </div>
        <div class="slds-p-around_medium lgc-bg">
            <c-child-L-W-C
                textreceived="this text is being propagated down" >
            </c-child-L-W-C>
        </div>
    </lightning-card>
</template>
import { LightningElement, track } from 'lwc';
export default class DataBindingExample extends LightningElement {
    @track textValue = 'testing data binding';
    
    handleTextChange(event){
        this.textValue = event.detail.value;
    }
}

In our example, function handleTextChange is the listener for the event thrown by the lightning-input when the text changes through the front-end. And in our new function, we just assign the value that comes in the payload of that event to our tracked property.

If you reproduce this code in your org, you will see that until we handle that event and then assign the event.detail.value to our tracked property, the value on the lightning-formatted-text will not change.

Pedro Molina February 18, 2020

Leave a Reply

Your email address will not be published. Required fields are marked *