carTile and carTileList Components

Building Our First LWC Component : In this section, we’ll start developing our Car Hub project by creating the carTile component. This component is responsible for displaying individual car details in a concise format, which will be used within the carTileList component to show multiple cars.

 

carTile.html
				
					<template>
    <div onclick={handleClick}>
        <div class="content">
            <img src={car.Picture_URL__c} class="slds-align_absolute-center carImage" alt="Car Picture"/>
            <div>
                <p class="title slds-align_absolute-center">{car.Name}</p>
                <p class="slds-align_absolute-center">
                    MSRP:
                    <lightning-formatted-number format-style="currency" currency-code="USD" value={car.MSRP__c} class="price"
                        maximum-fraction-digits="0"></lightning-formatted-number>
                </p>
            </div>
        </div>
    </div>
</template>
				
			
carTile.js
				
					import { LightningElement ,api} from 'lwc';
export default class CarTile extends LightningElement {
    @api car={};

    handleClick(event){
        const carId = new CustomEvent('selected',{
        detail: this.car.Id
        });
        this.dispatchEvent(carId);
    }
}
				
			
carTile.css
				
					img.carImage{
	height: 120px;
	max-width: initial;
	pointer-events: none;
}
.title{
	font-weight: bold;
	text-transform: uppercase;
}
.content{
	padding: 8px;
	background-color: white;
	border-radius: 0.25rem;
}
				
			
carTile.js-meta.xml
				
					<?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
	<apiVersion>57.0</apiVersion>
	<isExposed>true</isExposed>
	<targets>
		<target>lightning__RecordPage</target>
		<target>lightning__AppPage</target>
		<target>lightning__HomePage</target>
		<target>lightning__Tab</target>
	</targets>
</LightningComponentBundle>
				
			

Adding Message Channels: CarsSelected and CarsFiltered

In addition to building the carTile component, we’ll also set up two message channels: CarsSelected and CarsFiltered. These channels will facilitate event passing between components, allowing for seamless interaction and updates:

CarsSelected: This message channel will be used to pass information about the selected car from the Cars List component to the Car Details component.

CarsFiltered: This channel will handle the transmission of filter criteria from the Filter component to the Cars List component, ensuring that the car list updates according to the selected filters.

CarsFiltered
				
					<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
	<masterLabel>CarsFiltered</masterLabel>
	<isExposed>true</isExposed>
	<description>This event is fired when car filters change</description>
	<lightningMessageFields>
		<fieldName>filters</fieldName>
		<description>Current car filters</description>
	</lightningMessageFields>
</LightningMessageChannel>
				
			
CarsSelected
				
					<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
	<masterLabel>CarsSelected</masterLabel>
	<isExposed>false</isExposed>
	<description>This event is fired when car is selected</description>
	<lightningMessageFields>
		<fieldName>carId</fieldName>
		<description>CarSelectedId</description>
	</lightningMessageFields>
</LightningMessageChannel>
				
			
carTileList.html
				
					<template>
    <lightning-card title="Cars Available" icon-name="standard:calibration">
       <div class="slds-p-around-medium wrapper">
           <template if:true={cars.length}>
               <div class="content">
                   <template for:each={cars} for:item="car">
                       <c-car-tile key={car.Id} car={car} onselected={handleSelected}></c-car-tile>
                   </template>
               </div>
           </template>
           <template if:false={cars.length}>
               There are no car matching your current selection
           </template>
       </div>
    </lightning-card>
</template>
				
			
carTileList.js
				
					import { LightningElement,wire } from 'lwc';
import getCars from '@salesforce/apex/CarController.getCars';

// Lightning Message Service and a message channel
import {publish,subscribe,MessageContext} from 'lightning/messageService';
import CARS_FILTERED_MESSAGE from '@salesforce/messageChannel/CarsFiltered__c';
import CARS_SELECTED_MESSAGE from '@salesforce/messageChannel/CarsSelected__c';

export default class CarTileList extends LightningElement {
    cars={};
    filters={};
    carFilterSubscription;

    // Load Context for LMS
    @wire(MessageContext)
    messageContext

    @wire(getCars,{filters:'$filters'})
    carsHandler({data,error}){
        if(data){
            console.log('car list=>',data)
            this.cars = data;
        }
        if(error){
            console.error(error);
        }
    
    }

    connectedCallback() {
        this.subscribeHandler();
    }
    subscribeHandler(){
        this.carFilterSubscription = subscribe(this.messageContext,CARS_FILTERED_MESSAGE,(message)=>this.handleFilterChanges(message));
    }
    handleFilterChanges(message){
        console.log('message=>',message.filters);
        this.filters = {...message.filters};
    }
    handleSelected(event){
        console.log('selected car id=>',event.detail);
        publish(this.messageContext,CARS_SELECTED_MESSAGE,{
            carId: event.detail
        })
    }
    disconnectedCallback() {
        unsubscribe(carFilterSubscription);
        this.carFilterSubscription = null;
    }
}
				
			
carTileList.css
				
					c-car-tile{
	min-width: 200px;
	flex:1;
}
.content{
	display: flex;
	flex-wrap: wrap;
}
.wrapper{
	background:#e3e5e4;
	padding: 12px;
}
				
			
carTileList.js-meta.xml
				
					<?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
	<apiVersion>57.0</apiVersion>
	<isExposed>true</isExposed>
	<masterLabel>Car Tile List</masterLabel>
	<targets>
		<target>lightning__AppPage</target>
	</targets>
</LightningComponentBundle>
				
			

That’s it for today! We’ll pick up where we left off in the next blog post.

Article Information