Exercise 2Using Base Components

Objectives

  • Modify Apex to enable Lightning Component access.
  • Retrieve and display data based on search criteria.
  • Leverage Base Components to create the interface
  • Understand @api, @track and @wire
  • Encapsulate functionality into child components
  • Understand lightning:layout

Step 1 - Create the Apex Class Controller

  1. In VS Code, use the Command Palette to select SFDX: Create Apex Class. Name the class SimilarPropertyController and then hit return to save it into the default location.
  2. Replace the default code with:

     public with sharing class SimilarPropertyController {
    		
         public static List<Property__c> findProperties (Id recordId, Decimal priceRange) {
             List<Property__c> property = [SELECT Price__c FROM Property__c WHERE Id=:recordId];
             Decimal propertyPrice = property[0].Price__c;
             List<Property__c> similarProperties = getSimilarProperties(recordId, priceRange, propertyPrice);
             return similarProperties;
         }
    	    
         private static List<Property__c> getSimilarProperties (Id recordId, Decimal priceRange, Decimal price ) {
             Decimal range;
             if (priceRange == null) {
                 range = 100000;
             } else {
                 range = priceRange;
             }
             return [
                 SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                 FROM Property__c WHERE Id != :recordId AND Price__c > :price - range AND Price__c < :price + range
             ];
         }
     }
    
  3. Save the file.
  4. Add @AuraEnabled(cacheable=true) on the blank line above the findProperties method.
  5. Save the file.

Step 2 - Create the Similar Properties Component

  1. Use the Command Palette to select SFDX: Create Lightning Web Component.
  2. Name the component similarProperties.
  3. Paste the following code into similarProperties.html inside the <template> tag:

     <lightning-card title="Similar Properties"
                     icon-name="custom:custom85">
         <div class="slds-m-around_medium">
             <ul class="slds-list_vertical slds-has-dividers_top-space">
                 <template for:each={props.data} for:item="item" if:true={props.data}>
                     <li key={item.Id} class="slds-list__item">
                         {item.Name}
                     </li>
                 </template>
                 <template if:true={props.error}>
                   <li class="slds-list__item"><h3 class="slds-text-heading_small slds-text-color_error">{props.error}</h3></li>
                 </template>
             </ul>
         </div>
     </lightning-card>
    
  4. Add api,track,wire to the import from lwc in similarProperties.js.
  5. Add the following on a new line on line 2:

     import findProperties from '@salesforce/apex/SimilarPropertyController.findProperties';
    
  6. Add the following to the class:

     @api recordId;
     @track props;
     @track errorMsg;
    			
     @wire(findProperties, { 
         recordId: '$recordId',
         priceRange: '100000'
     })
     props
    
    
  7. Save the file.
  8. In the similarProperties.js-meta.xml, set <isExposed> to true.
  9. Add a label, description, and target after the <isExposed> tag:

    <masterLabel>Similar Properties</masterLabel>
    <description>This component searches for similar properties.</description>
    <targets>
      <target>lightning__RecordPage</target>
    </targets>
    
  10. Save the file.
  11. Push all the files to your scratch org.
  12. Go back to the Property Record page, click the Setup icon Setup icon and select Edit Page.
  13. Locate the similarProperties component under Custom components and drag it onto the page at the top of the right-hand column.
  14. Click Save in App Builder, and then Back.

    The page should now display a list of properties in the same price range.

Screenshot: SimilarProperties Lightning Component.

Step 3 - Create a Child Component

  1. Use the Command Palette to create a new component: SFDX: Create Lightning Web Component.
  2. Name the component similarProperty and save it in the default location.
  3. In similarProperty.js, import api from lwc.
  4. Add @api item; to the class definition.
  5. Save the file.
  6. Add {item.Name} on line 2 of similarProperty.html.
  7. Save the file.
  8. Go back to the similarProperties.html, and replace {item.Name} inside the <li> with:

     <c-similar-Property item={item}></c-similar-Property>
    
  9. Save the file and push to your scratch org.
  10. Refresh the Property Detail page.

    You shouldn’t notice any change.

Step 4 - Improve the Interface

  1. Replace {item.Name} in similarProperty.html with:

     <lightning-record-view-form object-api-name="Property__c"
                                 record-id={item.Id}>
         <lightning-output-field field-name="Name"></lightning-output-field>
     </lightning-record-view-form>
    
  2. Save the file and push to your scratch org, then refresh the Property Detail page.

    Screenshot: Similar Properties using lightning recordViewForm

  3. Add the following to the SimilarProperty.cmp after the initial lightning:outputField:

     <lightning-output-field field-name="Beds__c"></lightning-output-field>
     <lightning-output-field field-name="Baths__c"></lightning-output-field>
     <lightning-output-field field-name="Price__c"></lightning-output-field>
     <lightning-output-field field-name="Status__c"></lightning-output-field>
    
  4. Save the file and push to your scratch org, then refresh the Property Detail page.

    Screenshot: Similar Properties using lightning recordViewForm

  5. Replace the four lines of code you just pasted with the following:

     <lightning-layout multiple-rows>
       <lightning-layout-item size="6">
         <lightning-output-field field-name="Price__c"></lightning-output-field>
       </lightning-layout-item>
       <lightning-layout-item size="6">
         <lightning-output-field field-name="Beds__c"></lightning-output-field>
       </lightning-layout-item>
       <lightning-layout-item size="6">
         <lightning-output-field field-name="Baths__c"></lightning-output-field>
       </lightning-layout-item>
       <lightning-layout-item size="6">
         <lightning-output-field field-name="Status__c"></lightning-output-field>
       </lightning-layout-item>
       <lightning-layout-item size="12">
         <lightning-output-field field-name="Broker__c"></lightning-output-field>
       </lightning-layout-item>
     </lightning-layout>
    
  6. Save the file and push to your scratch org, then refresh the Property Detail page.

  7. Replace the contents of the <template> with the following:

         <div class="slds-media">
             <div class="slds-media__figure">
                 <img src={item.Thumbnail__c} class="slds-avatar_large slds-avatar_circle" alt={item.Title_c} />
                 </div>
                 <div class="slds-media__body">
                     <div class="slds-grid slds-hint-parent">
                         <a onclick={navigateToRecord}>
                         <h3 class="slds-text-heading_small slds-m-bottom_xx-small">{item.Name}</h3>
                       </a>
                     </div>
    	
                     <lightning-record-view-form object-api-name="Property__c"
                                                 record-id={item.Id}>
                         <lightning-layout multiple-rows>
                             <lightning-layout-item size="6">
                                 <lightning-output-field field-name="Price__c"></lightning-output-field>
                             </lightning-layout-item>
                             <lightning-layout-item size="6">
                                 <lightning-output-field field-name="Beds__c"></lightning-output-field>
                             </lightning-layout-item>
                             <lightning-layout-item size="6">
                                 <lightning-output-field field-name="Baths__c"></lightning-output-field>
                             </lightning-layout-item>
                             <lightning-layout-item size="6">
                                 <lightning-output-field field-name="Status__c"></lightning-output-field>
                             </lightning-layout-item>
                             <lightning-layout-item size="12">
                                 <lightning-output-field field-name="Broker__c"></lightning-output-field>
                             </lightning-layout-item>
                         </lightning-layout>
                     </lightning-record-view-form>
    	
                 </div>
             </div>
    
  8. Save the file and refresh the Property Detail page.

    Screenshot: Similar Properties component with lightning:layout

Something’s not quite right?

Check the code from your components against the following:

SimilarPropertyController.apxc
    public with sharing class SimilarPropertyController {
		@AuraEnabled(cacheable=true)
	    public static List<Property__c> findProperties (Id recordId, Decimal priceRange) {
	        List<Property__c> property = [SELECT Price__c FROM Property__c WHERE Id=:recordId];
	        Decimal propertyPrice = property[0].Price__c;
	        List<Property__c> similarProperties = getSimilarProperties(recordId, priceRange, propertyPrice);
	        return similarProperties;
	    }
	    
	    private static List<Property__c> getSimilarProperties (Id recordId, Decimal priceRange, Decimal price ) {
	        Decimal range;
	        if (priceRange == null) {
	            range = 100000;
	        } else {
	            range = priceRange;
	        }
	        return [
	            SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
	            FROM Property__c WHERE Id != :recordId AND Price__c > :price - range AND Price__c < :price + range
	        ];
	    }
	}
similarProperties.html
<template>
    <lightning-card title="Similar Properties"
                    icon-name="custom:custom85">
        <div class="slds-m-around_medium">
            <ul class="slds-list_vertical slds-has-dividers_top-space">
                <template for:each={props.data} for:item="item" if:true={props.data}>
                    <li key={item.Id} class="slds-list__item">
                        <c-sim-prop-child theitem={item}></c-sim-prop-child>
                    </li>
                </template>
                <template if:true={props.error}>
                  <li class="slds-list__item"><h3 class="slds-text-heading_small slds-text-color_error">{props.error}</h3></li>
                </template>
            </ul>
        </div>
    </lightning-card>
</template>
similarProperties.js
import { LightningElement,api,track,wire } from 'lwc';
import findProperties from '@salesforce/apex/SimilarPropertyController.findProperties';

export default class SimilarProperties extends LightningElement {
    @api recordId;
    @track props;
    @track errorMsg;

    @wire(findProperties, { 
        recordId: '$recordId',
        priceRange: '100000'
    })
    props
}
similarProperties.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="similarProperties">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Similar Properties</masterLabel>
    <description>This component searches for similar properties.</description>
    <targets>
      <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>
similarProperty.html
<template>
    <div class="slds-media">
        <div class="slds-media__figure">
            <img src={item.Thumbnail__c} class="slds-avatar_large slds-avatar_circle" alt={item.Title_c} />
            </div>
            <div class="slds-media__body">
                <div class="slds-grid slds-hint-parent">
                    <a onclick={navigateToRecord}>
                    <h3 class="slds-text-heading_small slds-m-bottom_xx-small">{item.Name}</h3>
                  </a>
                </div>

                <lightning-record-view-form object-api-name="Property__c"
                                            record-id={item.Id}>
                    <lightning-layout multiple-rows>
                        <lightning-layout-item size="6">
                            <lightning-output-field field-name="Price__c"></lightning-output-field>
                        </lightning-layout-item>
                        <lightning-layout-item size="6">
                            <lightning-output-field field-name="Beds__c"></lightning-output-field>
                        </lightning-layout-item>
                        <lightning-layout-item size="6">
                            <lightning-output-field field-name="Baths__c"></lightning-output-field>
                        </lightning-layout-item>
                        <lightning-layout-item size="6">
                            <lightning-output-field field-name="Status__c"></lightning-output-field>
                        </lightning-layout-item>
                        <lightning-layout-item size="12">
                            <lightning-output-field field-name="Broker__c"></lightning-output-field>
                        </lightning-layout-item>
                    </lightning-layout>
                </lightning-record-view-form>

            </div>
        </div>
</template>
similarProperty.js
import { LightningElement,api } from 'lwc';

export default class SimilarProperty extends LightningElement {
    @api item;
}