You are on page 1of 8

Modern App Development On Salesforce -

Communicate between LWC Components using


Events - Solution Key Activity2
Problem Statement
Create an LWC Component that displays Inventory List. Check the below screenshot. This is what we aim to build. 

Clicking on one of the items should focus only that item while muting other items(opacity of other items change to
0.45)

If you would like to watch the recordings where we live code, click this link

Solution
Tooling Prerequisites

You will need below tools installed

● Install Visual Studio Code


● Install Salesforce CLI 
● Install Salesforce Extension Pack For VSCode
● Install Local Development Server

Developer Environment

● You will need to sign up for a Salesforce Developer Account


● Enable DevHub and use Scratch orgs for development

Step By Step Code

Scaffold a LWC component with name inventoryCard and use the below markup
<template>
    <lightning-card>
        <lightning-badge
            label="Beta"
            class="slds-theme_success"
        ></lightning-badge>
        <p class="slds-var-p-horizontal_small">Card Body (custom component)</p>
    </lightning-card>
</template>

Use Local Development Server for previewing the component.

Align the Badge to the top right using slots

<template>
    <lightning-card>
        <lightning-badge
            label="Available"
            class="slds-theme_success"
            slot="actions"
        ></lightning-badge>
        <p class="slds-var-p-horizontal_small">Card Body (custom component)</p>
    </lightning-card>
</template>

Add Car Image

<template>
    <lightning-card>
        <lightning-badge
            label="Available"
            class="slds-theme_success"
            slot="actions"
        ></lightning-badge>
        <img
            src="https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.jpg"
            class="slds-align_absolute-center"
            alt="Vehicle picture"
        />
    </lightning-card>
</template>

Add the necessary text

<template>
    <lightning-card>
        <lightning-badge
            label="Available"
            class="slds-theme_success"
            slot="actions"
        ></lightning-badge>
        <img
            src="https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.jpg"
            class="vehicle slds-align_absolute-center"
            alt="Vehicle picture"
        />
        <p class="slds-var-m-horizontal_medium"><b>Title</b></p>
        <p class="slds-var-m-horizontal_medium">Package No</p>
        <p class="slds-var-m-horizontal_medium">VIN: 123</p>
    </lightning-card>
</template>

Make the component reusable and composable (Parent component can pass in the data) using decorators @api and
@track

<template>
    <lightning-card>
        <lightning-badge
            label={vehicle.status}
            class={vehicle.statusbadge}
            slot="actions"
        ></lightning-badge>
        <img
            src={vehicle.imageurl}
            class="vehicle slds-align_absolute-center"
            alt="Vehicle picture"
        />
        <p class="slds-var-m-horizontal_medium">
            <b>{vehicle.title}</b>
        </p>
        <p class="slds-var-m-horizontal_medium">{vehicle.packageNo}</p>
        <p class="slds-var-m-horizontal_medium">VIN: {vehicle.vin}</p>
    </lightning-card>
</template>

Create Inventory list Component 

inventoryList.html

<template>
    <lightning-layout>
        <template for:each={vehicles} for:item="vehicle">
            <lightning-layout-item padding="around-small" key={vehicle.vin}>
                <c-inventory-card vehicle={vehicle}> </c-inventory-card>
            </lightning-layout-item>
        </template>
    </lightning-layout>
</template>

inventoryList.js

import { LightningElement } from 'lwc';


export default class InventoryList extends LightningElement {

    vehicles = [
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "12323444"
        }

    ];
}

Expand the component to support n items

import { LightningElement } from 'lwc';
export default class InventoryList extends LightningElement {
    vehicles = [
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "12323444"
        },
        {
            "status" : "Sold",
            "statusbadge": "slds-theme_error",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_black.
            "title": "Model One",
            "packageNo" : "1235",
            "vin" : "12323445"
        },
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_red.jp
            "title": "Model One",
            "packageNo" : "1235e",
            "vin" : "12323447"
        },
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "1232344555"
        },
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "1232344555dd"
        }
    ];
}

At this point your template should look along below lines

<template>
    <lightning-layout horizontal-align="space" multiple-rows>
        <template for:each={vehicles} for:item="vehicle">
            <lightning-layout-item padding="around-small" key={vehicle.vin} size="4">
                <c-inventory-card vehicle={vehicle}> </c-inventory-card>
            </lightning-layout-item>
        </template>
    </lightning-layout>
</template>

Firing and Handling Events

Fire an onselect event from publisher component (inventoryCard). Create a css file inventoryCard.css as well.

inventoryCard.html

<template>
    <div class={vehicle.classStyle} onclick={handleClick}>
    <lightning-card>
        <lightning-badge
            label={vehicle.status}
            class={vehicle.statusbadge}
            slot="actions"
        ></lightning-badge>
        <img
            src={vehicle.imageurl}
            class="slds-align_absolute-center"
            alt="Vehicle picture"
        />
        <p class="slds-var-m-horizontal_medium">
            <b>{vehicle.title}</b>
        </p>
        <p class="slds-var-m-horizontal_medium">{vehicle.packageNo}</p>
        <p class="slds-var-m-horizontal_medium">VIN: {vehicle.vin}</p>
    </lightning-card>
    </div>
</template>

inventoryCard.js

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

export default class InventoryCard extends LightningElement {

    @api
    vehicle;

    handleClick() {
        console.log('clicked');
        const clickevt = new CustomEvent('cardselect',
                                {detail: { vin: this.vehicle.vin}});
        this.dispatchEvent(clickevt);      
    }
}

inventoryCard.css

.pointernotallowed {
    cursor: not-allowed;
}

.pointer {
    cursor: pointer
}

.mute {
    opacity: 50%;
    cursor: pointer;
}

Subscriber Component (Parent component inventoryList)

inventoryList.html

<template>
    <lightning-layout horizontal-align="space" multiple-rows>
        <template for:each={vehicles} for:item="vehicle">
            <lightning-layout-item padding="around-small" key={vehicle.vin} size="4">
                <c-inventory-card vehicle={vehicle} oncardselect={handleSelect}> </c-i
            </lightning-layout-item>
        </template>
    </lightning-layout>
</template>

inventoryList.js
import { LightningElement, track } from 'lwc';

export default class InventoryList extends LightningElement {

    @track
    vehicles = [
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "12323444",
            "classStyle": 'pointer'
        },

        {
            "status" : "Sold",
            "statusbadge": "slds-theme_error",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_black.
            "title": "Model One",
            "packageNo" : "1235",
            "vin" : "12323445",
            "classStyle": 'pointer'
        },

        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_red.jp
            "title": "Model One",
            "packageNo" : "1235e",
            "vin" : "12323447",
            "classStyle": 'pointer'
        },
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "1232344555",
            "classStyle": 'pointer'
        },
        {
            "status" : "Available",
            "statusbadge": "slds-theme_success",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_white.
            "title": "Model One",
            "packageNo" : "123",
            "vin" : "1232344555dd",
            "classStyle": 'pointer'
        },
        {
            "status" : "Sold",
            "statusbadge": "slds-theme_error",
            "imageurl": "https://sfdc-demo.s3-us-west-1.amazonaws.com/ecars/car_black.
            "title": "Model One",
            "packageNo" : "1235",
            "vin" : "123445",
            "classStyle": 'pointer'
        }
    ];

    handleSelect(event) {
        console.log(event);
        this.vehicles = this.vehicles.map((vehicle) => {
            if (event.detail.vin) {
                vehicle.classStyle = vehicle.vin === event.detail.vin ? 'pointernotall
            } else {
                vehicle.classStyle = 'pointer';
            }
            return vehicle;
        });
        console.log(this.vehicles);
    }
}

You can see how this component can be used in Salesforce App Builder page by deploying ecars Sample App.

You might also like