Monday, May 20, 2019

Import and Export in LWC.

Import and Export is very powerful feature which we will use in LWC. We know the word re-usability and generally we always try to use re-usable component for smart coding.
Here we will use ES6 module which is nothing but JS file that export variables or functions that other modules can use.
Basically to share our common code base between different components, we will create ES6 module and then export the variables or functions that we want to share or want to make as re-usable.

Scenario:
Say for our case we want to create a temperature calculator which will convert temperature from Celsius to Fahrenheit or vice versa. And we want to use this calculator from different components.

Solutions:
So, here we will create below 3 steps,

  • Create a JS file say temperatureCalculator.js and under this JS file, build our business logic like conversion of temperature from Celsius to Fahrenheit or vice versa.
  • Then export the function (where we implement our logic.).
  • Finally import the above re-usable component (temperatureDemo) from another component.
***************** Export Functionality *****************

temperatureCalculator.js
const convertCelsiusToFahrenheit = (c) => {
    return (9/5)*c + 32 ;
};

const convertFahrenheitToCelsius = (f) => {
    return 5/9 * (f-32);
};

export {
    convertCelsiusToFahrenheit,
    convertFahrenheitToCelsius
}


temperatureCalculator.js-meta.xml

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


***************** Import Functionality *****************

temperatureDemo.html
<template>
        <lightning-card title="Calculate Temperature">
            <lightning-layout>
                <lightning-layout-item>
                        <lightning-input type="number" label="Temperature" value={temp} onchange={fetchTemperature}></lightning-input>
                        <lightning-combobox label="Conversion Type" value={type} options={conversionType} onchange={fetchConversionType}></lightning-combobox>
                        <br/>
                        <lightning-button variant="brand" label="Calculate" onclick={calculateTemperature}></lightning-button>
                        {result}
                </lightning-layout-item>
            </lightning-layout>
        </lightning-card>
    </template>

temperatureDemo.js
import { LightningElement, track } from 'lwc';
import { convertCelsiusToFahrenheit } from 'c/temperatureCalculator';
import { convertFahrenheitToCelsius } from 'c/temperatureCalculator';

export default class TemperatureDemo extends LightningElement {
    @track type;
    @track temp;
    @track result;

    conversionType = [
        { label: "Celsius To Fahrenheit", value: "c2f" },
        { label: "Fahrenheit To Celsius", value: "f2c" }
    ];

    fetchTemperature(event){
        this.temp = event.target.value;
    }

    fetchConversionType(event){
        this.type = event.target.value;
    }

    calculateTemperature(){
        if(this.type === "c2f"){
            this.result = convertCelsiusToFahrenheit(this.temp);
        } else{
            this.result = convertFahrenheitToCelsius(this.temp);
        }                
    }
}

temperatureDemo.js-meta.xml

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

Now put this temperatureDemo LWC component in your Lightning Page and check the result.

Output:

Initial load:























After button click:

Publish Subscribe Pattern in LWC (Component Communication).

1. publish-subscribe pattern/model is same like Application Event in Lighting Component. If you want to communicate between components those are not bounding in parent child relationship, but available in same page (say, in same app-builder page), then we will use publish-subscribe pattern. Here Salesforce already publish a pubsub.js file which we will use. You can download pubsub.js file from below link or copy paste below pubsub.js.
https://github.com/trailheadapps/lwc-recipes/blob/master/force-app/main/default/lwc/pubsub/pubsub.js

Now create a LWC component named as pubsub and update the pubsub.js file with downloaded code base or copy paste below source code,

/**
 * A basic pub-sub mechanism for sibling component communication
 *
 * TODO - adopt standard flexipage sibling communication mechanism when it's available.
 */

const events = {};

const samePageRef = (pageRef1, pageRef2) => {
    const obj1 = pageRef1.attributes;
    const obj2 = pageRef2.attributes;
    return Object.keys(obj1)
        .concat(Object.keys(obj2))
        .every(key => {
            return obj1[key] === obj2[key];
        });
};

/**
 * Registers a callback for an event
 * @param {string} eventName - Name of the event to listen for.
 * @param {function} callback - Function to invoke when said event is fired.
 * @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
 */
const registerListener = (eventName, callback, thisArg) => {
    // Checking that the listener has a pageRef property. We rely on that property for filtering purpose in fireEvent()
    if (!thisArg.pageRef) {
        throw new Error(
            'pubsub listeners need a "@wire(CurrentPageReference) pageRef" property'
        );
    }

    if (!events[eventName]) {
        events[eventName] = [];
    }
    const duplicate = events[eventName].find(listener => {
        return listener.callback === callback && listener.thisArg === thisArg;
    });
    if (!duplicate) {
        events[eventName].push({ callback, thisArg });
    }
};

/**
 * Unregisters a callback for an event
 * @param {string} eventName - Name of the event to unregister from.
 * @param {function} callback - Function to unregister.
 * @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
 */
const unregisterListener = (eventName, callback, thisArg) => {
    if (events[eventName]) {
        events[eventName] = events[eventName].filter(
            listener =>
                listener.callback !== callback || listener.thisArg !== thisArg
        );
    }
};

/**
 * Unregisters all event listeners bound to an object.
 * @param {object} thisArg - All the callbacks bound to this object will be removed.
 */
const unregisterAllListeners = thisArg => {
    Object.keys(events).forEach(eventName => {
        events[eventName] = events[eventName].filter(
            listener => listener.thisArg !== thisArg
        );
    });
};

/**
 * Fires an event to listeners.
 * @param {object} pageRef - Reference of the page that represents the event scope.
 * @param {string} eventName - Name of the event to fire.
 * @param {*} payload - Payload of the event to fire.
 */
const fireEvent = (pageRef, eventName, payload) => {
    if (events[eventName]) {
        const listeners = events[eventName];
        listeners.forEach(listener => {
            if (samePageRef(pageRef, listener.thisArg.pageRef)) {
                try {
                    listener.callback.call(listener.thisArg, payload);
                } catch (error) {
                    // fail silently
                }
            }
        });
    }
};

export {
    registerListener,
    unregisterListener,
    unregisterAllListeners,
    fireEvent
};

2. Now we have to create two more components, one will be used to publish an event and another will be used to subscribe the event. Say, our publisher component name is myPublisher and our subscriber component is mySubscriber.

3.  ************* Publisher Component Details. *************

myPublisher.html
<template>
    <lightning-card title="Publisher Component">
        <lightning-layout>
            <lightning-layout-item>
                <button onclick={displayLabradorDetails}>Labrador</button>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

myPublisher.js
import { LightningElement, wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import { fireEvent } from 'c/pubsub';

export default class MyPublisher extends LightningElement {
    @wire(CurrentPageReference) pageRef;

    displayLabradorDetails(){
        fireEvent(this.pageRef, "eventdetails", "Breed - Labrador");
    }
}

myPublisher.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="myPublisher">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>


4.  ************* Subscriber Component Details. *************

mySubscriber.html
<template>
    <lightning-card title="Subscriber Component">
        <lightning-layout>
            <lightning-layout-item>
                {details}
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

mySubscriber.js
import { LightningElement, track, wire } from 'lwc';
import { registerListener, unregisterAllListeners } from 'c/pubsub';
import { CurrentPageReference } from 'lightning/navigation';

export default class MySubscriber extends LightningElement {
    @track details;
    @wire(CurrentPageReference) pageRef;

    connectedCallback() {
        registerListener("eventdetails", this.sutUpDetails, this);
    }
     
    disconnectedCallback() {
        unregisterAllListeners(this);
    }

    sutUpDetails(dogDtl){
        this.details = dogDtl;
    }
}

mySubscriber.js-meta.xml

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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>

5. Now authorize your Org and then deploy all above 3 LWC components in your authorized Org and finally drag myPublisher and mySubscriber in your Lightning Page.

6. Output ==>

Initial Load:


















After click on button:

Saturday, May 18, 2019

Custom Event in LWC.

Custom Event in LWC is same like Component Event in Lightning Component. Communicate from parent to child component can be done using passing property value or calling method of child component from parent component.
But if the communication is reverse i.e. communication from child to parent component then we can use Custom Event.
Here the technique is different with respect to Lighting Component.

In child component JS file, we have to CREATE and DISPATCH the the event.
To create an event, use the CustomEvent() constructor. And then we use dispatchEvent() method to dispatch the event.

customEventChildComp.html
<template>
    <lightning-button label="Pass message from child component" onclick={handleCustomEvent}></lightning-button>
</template>

customEventChildComp.js
import { LightningElement } from 'lwc';

export default class CustomEventChildComp extends LightningElement {
    handleCustomEvent(){
        //Use the CustomEvent() constructor to create an event. And always use event name in lower case.
        const myCustomEvent = new CustomEvent("displaymessage", { detail: "Message Passing from child component using custom event." });

        //Use dispatchEvent() method to dispatch the above created event.
        this.dispatchEvent(myCustomEvent);
    }
}

Now we can listen event from parent in 2 ways,

1. Declaratively from the component’s HTML template :
2. Programmatically using an imperative JavaScript API :

Note: It’s better to listen from the HTML template since it reduces the amount of code you need to write.

customEventParentComp.html
<template>
    <lightning-card title="Custom Event Example.">
            <lightning-layout>
                <lightning-layout-item>
                    {messageFrmChild}<br/>
                    <!-- Declaratively listen custom event. Use 'on' prefix before event name declared in child component named as 'displaymessage' -->
                    <c-custom-event-child-comp ondisplaymessage={handelMessageFromChild}></c-custom-event-child-comp>
                </lightning-layout-item>
            </lightning-layout>
        </lightning-card>
</template>

customEventParentComp.js
import { LightningElement, api } from 'lwc';

export default class CustomEventParentComp extends LightningElement {
    @api
    messageFrmChild;
    handelMessageFromChild(event){
        this.messageFrmChild = event.detail;
    }
}

customEventParentCompjs-meta.xml

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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>


Then open any existing appBuilder / create a new one and drag the <parentComponent> in to respective column and then save and activate it.  Now click the tab to show it in browser and it will look as follows,

Output ==>
Before calling event













After calling event by button click

Getter Setter Method in LWC.

1. Create a LWC component named as "getterSetterExample". Where getterSetterExample.js has a getter and a setter method for "greetingMessage" and in "getterSetterExample.html" we will call "greetingMessage" message
to display.

getterSetterExample.html
<template>
    {greetingMessage}
</template>

getterSetterExample.js
import { LightningElement, api } from 'lwc';

export default class GetterSetterExample extends LightningElement {
    
    //Get method use to return greeting message.
    @api
    get greetingMessage(){
        return this._greetingMessage;
    }

    //Set method use to setup greeting message in upper case.
    set greetingMessage(value){
        this._greetingMessage = value.toUpperCase();
    }
}


2. Now call this "getterSetterExample" component from "useGetterSetter" component.

useGetterSetter.html
<template>
    <lightning-card title="Getter Setter Example">
        <lightning-layout>
            <lightning-layout-item>
                <!-- Passing greeting-message in small letter and expected result: message will be shown in capital letter. -->
                <c-getter-setter-example greeting-message="hello everyone. welcome to lwc getter setter example."></c-getter-setter-example>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

Now to make this useGetterSetter available in AppBuilder/Record Page/Home Page, please update "useGetterSetter.js-meta.xml" file as below,

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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>


3. Then open any existing appBuilder / create a new one and drag the <useGetterSetter> in to respective column and then save and activate it.  Now click the tab to show it in browser and it will look as follows,















4. So, we are passing value of "greeting-message" property of "getterSetterExample" LWC component from "useGetterSetter" LWC component, in small letter as "hello everyone. welcome to lwc getter setter example.".
Now this message will be set in upper case in setter method of "getterSetterExample.js" file and from getter method it will return the value.
So, while calling child component (getterSetterExample) from parent component (useGetterSetter) with above message (in small letter), then system will display the message in capital letter. And the output is as follows,


Calling child method form parent (Parent Child Communication).

1. childComponent.html

<template>
    {childComMessage}
</template>

2. childComponent.js
import { LightningElement, api } from 'lwc';

export default class TestMyLwcComp extends LightningElement {
    @api childComMessage;

    @api
    messageFromChild(){
        this.childComMessage = "Message set from child method...........";
    }
}

3. parentComponent.html

<template>
    <lightning-card title="Parent Component">
        <lightning-layout>
            <lightning-layout-item>
                <c-child-component></c-child-component>
                <button onclick={displayChildMessage}>Display Child Message</button>
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

4. parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComp extends LightningElement {

    displayChildMessage(){
        this.template.querySelector('c-child-component').messageFromChild();
    }
}

5. Now to make this parentComponent available in AppBuilder/Record Page/Home Page, please update "parentComponent.js-meta.xml" file as below,

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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>

6. Now deploy it to your authenticated ORG. If you are not authenticated any ORG till now then click  [Ctrl + Shift + P] and in command pallet type "Authorize an Org" and select "Authorize an Org" and from browser authenticate your destination ORG where you want to deploy parent and child component.

7. Then open any existing appBuilder / create a new one and drag the <parentComponent> in to respective column and then save and activate it.  Now click the tab to show it in browser and it will look as follows,

Initial load















After click on <Display Child Message> button.

Pass properties value from parent to child component (Parent Child Communication)

Objective of this post is to shown you how to call a child component from a parent component and also how to pass child component's property's value from parent component.

If you have existing project then you can use that or create a new project as describe in my previous post.

1. Create a child component named as "childComponent" and parent component named as "parentComponent".























2. Open "childComponent.js" file and add a string property (childComMessage) as follows,

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api childComMessage;
}

3. Open "childComponent.html" file and modify it with below code to display childComMessage.


<template>
    {childComMessage}
</template>

4. Now we want to call this childComponent from parentComponent. So, open parentComponent.html and modify it with below code,


<template>
    <lightning-card title="Parent Component">
        <lightning-layout>
            <lightning-layout-item>
                <c-childComponent></c-childComponent>    
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

5. Now we want to pass value of "childComMessage" property of childComponent. So, modify the code base of parentComponent.html again as below,


<template>
    <lightning-card title="Parent Component">
        <lightning-layout>
            <lightning-layout-item>
                <c-child-component child-com-message="Child component property's value passing from parent component."></c-child-component>    
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
</template>

Note: 
In child component (childComponent) and it's property name is "childComMessage" and is in "CAMEL" case, but while calling it from another component, child component and it's property should be written in "KEBAB" Case.
So, childComponent (camel case) should be like child-component (kebab case).
and childComMessage (camel case) should be like child-com-message (kebab case).

6. Now to make this parentComponent available in AppBuilder/Record Page/Home Page, please update "parentComponent.js-meta.xml" file as below,

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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>

7. Now deploy it to your authenticated ORG. If you are not authenticated any ORG till now then click  [Ctrl + Shift + P] and in command pallet type "Authorize an Org" and select "Authorize an Org" and from browser authenticate your destination ORG where you want to deploy parent and child component.

8. Then open any existing appBuilder / create a new one and drag the <parentComponent> in to respective column and then save and activate it. Now click the tab to show it in browser and it will look as follows,

SFDX + Visual Studio (Software Setup) + Create your first LWC component.

Please check my previous blog post (SFDX Setup Guide.) to setup SFDX,
http://sfdccodepractices.blogspot.com/2019/01/sfdx-setup-guide.html

Once you install SFDXCLI, then download Visual Studio (link: https://code.visualstudio.com/) and install Visual Studio.
Once VS is installed, open the IDE and click on "Extensions" link.
Then search for "Salesforce Extension Pack" and install the plugin.








Once "Salesforce Extension Pack" is installed successfully, then your software' configuration for your first LWC program is ready and it's time to implement your first Lightning Web Component.

1. Click => Ctrl + Shift + P  and it will open a Command Palette.







2. Type "Create Project" in Command Palette search box and select "Create Project" option and then enter.







3. Then it will ask for your project name. Enter your project name like "MyFirstLWCProject" and then click and it will redirect to your local directory, where you want to create your project.




4. Now you will see a project structure has been created and it is displayed in your EXPLORER panel. Number of files and folders will be created here, so don't panic. We will discussed these later. Just focus on your first LWC component.



















5. Now select your project "MyFirstLWCProject" and again click [Ctrl + Shift + P] and then type "Create Lightning Web Component" in Command Palette and select the "Create Lightning Web Component".





6. Then system will ask for "enter desire file name" and then type your file name like "myFirstLightningWebComponent" and enter.

7. Then system will ask for "enter desire directory". Select the default one (force-app/main/default/lwc) or just press enter.

8. So, under force-app/main/default/lwc --> a new folder will be created named as "myFirstLightningWebComponent" and also under this folder 3 files will be created as,
  • myFirstLightningWebComponent.html ==> Here you write your markup.
  • myFirstLightningWebComponent.js ==> Here you implement your client side business logic.
  • myFirstLightningWebComponent.js-meta.xml ==> Here you configure your component setup, like where you want to expose your component like under record page or under app page etc. 
You can check the files in your local directory or in explorer. If it is not reflected in explorer, then just refresh the explorer.







9. Click on myFirstLightningWebComponent.js-meta.xml and update the content as below,


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

    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>   
    </targets>
</LightningComponentBundle>

10. Now click on myFirstLightningWebComponent.html file and update it as below,


<template>
    <lightning-card title="Welcome To LWC World">
        <lightning-layout>
            <lightning-layout-item>
                This is my first Lightning Web Component.
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
    
</template>

11. Currently for simplicity we are not touching myFirstLightningWebComponent.js file.

12. Now its time to deploy your LWC component in your ORG. So, first select your project and then click  [Ctrl + Shift + P] and finally in command pallet type "Authorize an Org" and select "Authorize an Org" and then just enter twice (keep the section default as it is.).
It will redirect to login.salefoce.com. Enter your Org credentials. Now your component is ready to deploy in this login Org.







13. Now right click on your "myFirstLightningWebComponent" folder from explorers and then click on "SFDX:Deploy Source to Org" and if every thing is OK then your component will be deployed to your authorise Org.





















14. Once deployed successfully, then you can check your lightning component in your ORG.





















15. Go to Lighting App Builder and then create a new App Page (MyFirstLwc). Drag your "myFirstLightningWebComponent" in to "MyFirstLwc". Than save and activate it.




13. Open App Launcher and click "MyFirstLwc" and it will show your LWC component.

14. Now make this example little complex. Display some message coming from myFirstLightningWebComponent.js file. So, add a variable under myFirstLightningWebComponent.js and then access it from myFirstLightningWebComponent.html.

myFirstLightningWebComponent.js

import { LightningElement } from 'lwc';

export default class MyFirstLightningWebComponent extends LightningElement {
    message = "Enjoy Your Learning.";
}

myFirstLightningWebComponent.html

<template>
    <lightning-card title="Welcome To LWC World">
        <lightning-layout>
            <lightning-layout-item>
                This is my first Lightning Web Component.
                {message}
            </lightning-layout-item>
        </lightning-layout>
    </lightning-card>
    
</template>

15. Deploy it again.

16. Run the program in browser and it will show as below output screen,


Thursday, May 9, 2019

Lightning Web Component (LWC).

What is Lightning web component?

Lightning web component is a new framework to create Lightning Component and is a custom HTML elements built using  HTML and modern JavaScript.


Advantage :
  • Low custom code is required as LWC is built on web standards for almost all of the code involved.
  • No more static resource is required. You can write reusable component (comp-1) that has no UI and then export it (comp-1) to use it (comp-1) by another component (comp-2) and to use the export component (comp-1),  just import it from another component ((comp-2) . 
  • In LWC less apex needs to write and hence calling apex is less painful experience.


Difference between Lightning Component and Lightning Web Component?
  1. The main difference is that Lightning Component is built on open source aura framework, where LWC is built on standard web technologies like HTML, modern JavaScript, CSS, XML etc.
  2. There is no import/export functionality in Lightning Component, but in LWC support import/export feature which reduce use of static resource and increase use of reusable component.

What you need to know before start LWC?
  1. SFDX.
  2. Visual Studio.
  3. Web Component.

UI part of LWC is implemented by HTML, but Salesforce Org don't support HTML, then how its work?

We can't create LWC component using Salesforce Developer Console. To create it we generally use Visual Studio IDE and use SFDX for deployment. So, when we create LWC component using Visual Studio it will create a bundle which contains HTML, JS, XML and CSS (by default).
Next step is to deploy that component in a Salesforce Org. While deploying that bundle in any Salesforce Org, Salesforce internally handle all the source code and expose only that component's name to use by user.


Web Component:
Web Components is used to create REUSABLE CUSTOM ELEMENTS. Web Component is basically consists of 3 main technologies,
  1. HTML Templates,
  2. Custom Elements,
  3. Shadow DOM

1. HTML Templates:
HTML Templates is allow us to write markup under <template> tag.

Ex. Create a html file say <index.html> and use <template> tag as below,

<template>
 <p>I am under HTML template tag.</p>
</template>

Now, execute/run this <index.html> in browser.

What is display in browser?

Expected Result: As per above html context browser should show "I am under HTML template tag." as a paragraph format.
Actual Result : Blank page. No content :(

Why browser is not showing anything?

Contents/Markup implemented under <template> tag will not rendered automatically. Actually the contents under template tag are not rendered in the DOM.
This <template> tag is part of HTML5 and is very powerful tag. This can be reused number of times (reusable) as the basis of a custom element's structure.

So, how to display the content in browser?

This template should be initiated by a JavaScript.

Example: Used the above <index.html> under a folder and modify it with a template Id as shown below,
<template id="myTemplate">
 <p>I am under HTML template tag.</p>
</template>

Now under same folder create a JavaScript file say named as "myJs.js" and fetch the template reference by template id and append it to the DOM.
Below are the sample JS code.
Example.
// newer feature
function loadTemplate1(){
 var template = document.querySelector("#myTemplate");
 var cloneTemplate = template.content.cloneNode(true);
 document.body.appendChild(cloneTemplate);
}

//older feature
function loadTemplate2(){
 let template = document.getElementById('myTemplate');
 let templateContent = template.content;
 document.body.appendChild(templateContent);
}

Now again modify the <index.html> to load the JavaScript.
<script src="myJs.js"></script>
<body onload="loadTemplate1();">
   <template id="myTemplate">
     <p>I am under HTML template tag...</p>
   </template>
</body>

Finally execute/run this index.html and it will display "I am under HTML template tag." as a paragraph format.


2. Custom Elements

This is the second part of Web Component. Here we can create our own tag and then we can use it in HTML. To build custom element, here we will use the above index.html and myJs.js file.
Suppose we want to create a custom tag named as "my-custom-tag" and want to use it under index.html. Now for simplicity let say this tag only display some string message.

So, the html is look as below,
<script src="myJs.js"></script>
<body onload="loadTemplate1();">
 <template id="myTemplate">
  <p>I am under HTML template tag...</p>
  
  <my-custom-tag></my-custom-tag>
 </template>
</body>

Now we have to create custom tag named as "my-custom-tag" under myJs.js file and the js will be as follows,

// newer feature
function loadTemplate1(){
 var template = document.querySelector("#myTemplate");
 var cloneTemplate = template.content.cloneNode(true);
 document.body.appendChild(cloneTemplate);
}

//Create a class that extends out of the box HTMLElement class.
class MyCustomTag extends HTMLElement{
 constructor(){
  super();
  
  this.innerHTML = '<p>This Message is coming from my custom tag.<p>';
 }
}

//Now define your custom tag logic under a user friendly tag.
customElements.define('my-custom-tag', MyCustomTag);

After execute/run the index.html, it will display below contents in browser.

I am under HTML template tag...

This Message is coming from my custom tag.


3. Shadow DOM

Encapsulation is an important aspect of web components. Shadow DOM can encapsulate the behavior (markup, style etc.) from main DOM.
Let take an example, take the previous example describe under Custom Element section. So, here we have 2 files index.html and myJs.js.
Under html we are using a paragraph (<p>) tag and in js file we are also using a paragraph (<p>) while creation of custom elements (my-custom-tag).

Now we want to show all paragraph contents with RED color. So, what we have to do? We have to create a CSS file (myCss.css) where we mentioned paragraph color as RED and the total code base will look like below,

index.html
<script src="myJs.js"></script>
<link rel="stylesheet" href="myCss.css">
<body onload="loadTemplate1();">
 <template id="myTemplate">
  <p>I am under HTML template tag...</p>
  
  <my-custom-tag/></my-custom-tag>
 </template>
</body>

myJs.js
// newer feature
function loadTemplate1(){
 var template = document.querySelector("#myTemplate");
 var cloneTemplate = template.content.cloneNode(true);
 document.body.appendChild(cloneTemplate);
}

//Create a class that extends out of the box HTMLElement class.
class MyCustomTag extends HTMLElement{
 constructor(){
  super();
  
  this.innerHTML = '<p>This Message is coming from my custom tag.<p>';
 }
}

//Now define your custom tag logic under a user friendly tag.
customElements.define('my-custom-tag', MyCustomTag);

myCss.css
p {
  color: red;
}

Output (red color):

I am under HTML template tag...

This Message is coming from my custom tag.

Here we have to note that we have a common CSS (myCss.css) file, which will made all paragraph's content as RED color.
Now, if we use style (paragraph color as BLUE) under custom elements, then as per Shadow DOM feature it will encapsulate main DOM RED color for paragraph.
So, result will RED color for "I am under HTML template tag..." and BLUE color for "This Message is coming from my custom tag.".

myJs.js

// newer feature
function loadTemplate1(){
 var template = document.querySelector("#myTemplate");
 var cloneTemplate = template.content.cloneNode(true);
 document.body.appendChild(cloneTemplate);
}

//Create a class that extends out of the box HTMLElement class.
class MyCustomTag extends HTMLElement{
 constructor(){
  super();
  
  this.innerHTML = "<p style='color:blue'>This Message is coming from my custom tag.<p>";
 }
}

//Now define your custom tag logic under a user friendly tag.
customElements.define('my-custom-tag', MyCustomTag);

Output:

I am under HTML template tag...

This Message is coming from my custom tag.

LWC to LWC Communication using Lightning Messaging Service (Part - 2)

In my previous post ( previous post link ) we have learn how to create a Lightning Messaging Service with 6 steps and today we will use the ...