Track Decorator in Lightning Web Component (LWC) : jayakrishnasfdc

Track Decorator in Lightning Web Component (LWC)
by: jayakrishnasfdc
blow post content copied from  Jayakrishna Ganjikunta
click here to view original post


Decorators

The Lightning Web Components programming model has three decorators that add functionality to a property or function.

The ability to create decorators is part of ECMAScript, but these three decorators are unique to Lightning Web Components.
1) @track
2) @api
3) @wire
Systax to Decorate a property
@decoratorName propertyName=’propertyValue’;
Sytax to decorate a method
@decoratorName getMethodName(){
return somevalue;
}

1. track decorator 

The fundamental way detects the DOM changes is through tracked properties. Tracked properties are just like normal properties on your component but these properties are private property’s value and re-render a component when it changes. decorate property is annotated with @track.
Tracked properties are also called private reactive properties mean the changes will reflect only in the component.
You can use a tracked property directly in a template. You can also use a tracked property indirectly in a getter of a property that’s used in a template.

Now Let’s take an lightning web component(trackDecorator.html) that contains properties that will update the value to the UI based on the user interface changes

use this code in decorator.html. The Markup contains the input field that will re-render the values to the UI based on the input change.

trackDecorator.html

<template>
    <lightning-card title="Track Decorators Example">
        <div class="slds-m-around_medium">
           <lightning-input value={message} 
            label="Private Property"
            placeholder="enter your input here"
            onchange={handleChange}></lightning-input>
        <div>
            message is : {message}
        </div>
        </div>
    </lightning-card>
</template>

use the below trackDecorator.js code. the code contains one property inputMessage.

trackDecorator.js

import {
    LightningElement
} from 'lwc';

export default class TrackDecorator extends LightningElement {
    {
    message = 'Hello World';

    handleChange(event){
        this.message = event.target.value;
        console.log(' Updated Message is ', this.message);
    }
}

trackdecorator.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="trackDecorator">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

After deploying to source org, In the below screenshot shows the property values are updating in the controller and the changes won’t reflect in the UI .

Now update the property with @track decorator which makes the property as trackable property means the changes in the controller will update the UI.

Update the trackDecorator.js JavaScript controller with below code and push the changes

import {
    LightningElement,track
} from 'lwc';

export default class TrackDecorator extends LightningElement {
    @track inputMessage = 'World';

    handleChange(event) {
        console.log('event.target.value' + event.target.value);
        this.inputMessage = event.target.value;
    }
}

Now you can able to see the changes will reflect on the UI  as shown below.

limitation of the track decorators

As of now, we are seeing the inputMessage property is changes are reflected on UI from the JavaScript controller and now let’s try to pass the values from app builder into the inputMessage property.

update the trackDecorator.js-meta.xml and push the changes to the scratch org.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="trackDecorator">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <property name="inputMessage" type="String" label="inputMessage" placeholder="World" description="Enter the name of the person to greet."/>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Now you will get the below error message by saying the inputMessage property does not exist because this property is tracked properties and which is private.

And the second limitation with @track property is you can’t pass the property form the parent component. create a new web component

  1. You can’t expose these properties to app builder
  2. You can’t pass the properties from the other components. tracked properties are also called private reactive properties. and let’s see how to fix these two issues using @api decorator

2. api decorator

To expose a public property, decorate it with @api.
An owner component that uses the component in its markup can access the component’s public properties. Public properties are reactive. If the value of reactive property changes, the component’s template rerenders any content that references the property. To expose a public method, decorate it with @api. Public methods are part of a component’s API. You can use a JavaScript method to communicate down the containment hierarchy. For example, an owner calls a method on a child component that it contains.

By using @api decorator to solve the two limitations with @track.

update apiDecorator.html markup with the below code.

<template>
    <lightning-card title=" API Decorators Example">
        <div class="slds-m-around_medium">
            <p>Message , {inputMessage}!</p>
            <lightning-input label="Message" value={inputMessage} onchange={handleChange}></lightning-input>
        </div>
    </lightning-card>
</template>

apiDecorator.js

import {
    LightningElement,api
} from 'lwc';

export default class ApiDecorator extends LightningElement {
    @api inputMessage = 'World';

    handleChange(event) {
        console.log('event.target.value' + event.target.value);
        this.inputMessage = event.target.value;
    }
}

use the apiDecorator.js-meta.xml code

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="apiDecorator">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__AppPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <property name="inputMessage" type="String" label="inputMessage" placeholder="World" description="Enter the name of the person to greet."/>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Push changes to scratch org and add this component to the layout using app builder and now you can able to see the inputMessage property is configured from the app builder as shown below.

  1. Expose the property as public property
  2. Expose the property to the App Builder
  3. Pass the property values  from the parent component

3.wire decorator

if we want to get the inputMessage from the apex class you need to use @wire .

@wire To read Salesforce data, Lightning web components use a reactive wire service. When the wire service provisions data, the component rerenders. Components use @wire in their JavaScript class to specify a wire adaptor or an Apex method.

Message.cls
public with sharing class Message {
     @AuraEnabled(cacheable=true)
    public static String getInpMessage() {
        return 'Input Message from Apex Class';
    }
}

update the  wiredecorator.js with below code

import {
    LightningElement,
    api,wire
} from 'lwc';

import getInpMessage from '@salesforce/apex/Message.getInpMessage';
export default class Hello2 extends LightningElement {
    @api inputMessage = 'World';

    @wire(getInpMessage) inputMessage;

    handleChange(event) {
        console.log('event.target.value' + event.target.value);
        this.inputMessage = event.target.value;
    }
}

you can able to see the inputMessage property values is coming from the apex class.


December 06, 2020 at 10:12AM
Click here for more details...

=============================
The original post is available in Jayakrishna Ganjikunta by jayakrishnasfdc
this post has been published as it is through automation. Automation script brings all the top bloggers post under a single umbrella.
The purpose of this blog, Follow the top Salesforce bloggers and collect all blogs in a single place through automation.
============================

Salesforce