Summer '24 で認定 JavaScript デベロッパー資格を更新する


Summer '24 で認定 JavaScript デベロッパー資格を更新する
https://trailhead.salesforce.com/ja/content/learn/modules/javascript-developer-i-certification-maintenance-summer-24/maintain-your-javascript-developer-i-certification-for-summer-24

うまくいかなかったので、メモっておく

```javascript:boatPicker.js
import { LightningElement, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import BOAT_PICTURE_FIELD from "@salesforce/schema/Boat__c.Picture__c";
import BOAT_NAME_FIELD from "@salesforce/schema/Boat__c.Name";
import BOAT_OWNER_FIELD from "@salesforce/schema/Boat__c.Contact__r.Name";
import BOAT_PRICE_FIELD from "@salesforce/schema/Boat__c.Price__c";
import BOAT_TYPE_FIELD from "@salesforce/schema/Boat__c.BoatType__r.Name";
const BOAT_FIELDS = [BOAT_PICTURE_FIELD, BOAT_NAME_FIELD,BOAT_OWNER_FIELD, BOAT_PRICE_FIELD, BOAT_TYPE_FIELD];
export default class Boats extends LightningElement {   
    boatId;
    get showBoat() {
        return this.boatId != null;
    }
    @wire(getRecord, { recordId: '$boatId', fields: BOAT_FIELDS  })
    boatDetail;
    displayInfo = {
        primaryField: 'Name',
        additionalFields: ['BoatType__r.Name'],
    };
    matchingInfo = {
        primaryField: { fieldPath: 'Name' },
        additionalFields: [{ fieldPath: 'BoatType__r.Name' }],
    };
    // BEGIN GETTERS FOR BOAT FIELDS
    get boatPicture() {
        return getFieldValue(this.boatDetail.data, BOAT_PICTURE_FIELD);
    }
    get boatName() {
        return getFieldValue(this.boatDetail.data, BOAT_NAME_FIELD);
    }
    get boatOwner() {
        return getFieldValue(this.boatDetail.data, BOAT_OWNER_FIELD);
    }
    get boatPrice() {
        return getFieldValue(this.boatDetail.data, BOAT_PRICE_FIELD);
    }
    get boatType() {
        return getFieldValue(this.boatDetail.data, BOAT_TYPE_FIELD);
    }
    // END GETTERS FOR BOAT FIELDS
    get backgroundStyle() {
        if (!this.showBoat) {
            return '';
        } else {
            return `background-image:url('${this.boatPicture}')`;
        }
    }
    handleChange(event) {
        this.boatId = event.detail.recordId;
    }
}
```

```html:boatPicker.html
<template>
    <lightning-card title="Boat Browser">
        <div class="slds-var-p-horizontal_medium">
            <div class="slds-var-m-bottom_medium">
                <lightning-record-picker
                    label="Browse our inventory"
                    placeholder="Search by boat name or type"
                    object-api-name="Boat__c"
                    value={boatId}
                    display-info={displayInfo}
                    matching-info={matchingInfo}
                    onchange={handleChange}>
                </lightning-record-picker>
            </div>
            <div lwc:if={showBoat}>
                <div class="tile slds-var-m-vertical_medium" >
                    <div style={backgroundStyle} class="tile"></div>
                </div>
                <div class="slds-text-heading_medium slds-border_bottom slds-var-m-bottom_medium">{boatName}</div>
                <div>Captain: {boatOwner}</div>
                <p>Price: <lightning-formatted-number maximum-fraction-digits="0" value={boatPrice} format-style="currency" currency-code="USD"></lightning-formatted-number></p>
                <div>Type: {boatType}</div>
            </div>
        </div>
    </lightning-card>
</template>
```

```css:boatPicker.css
.tile {
    width: 100%;
    height: 220px;
    padding: 1px !important;
    background-position: center;
    background-size: cover;
    border-radius: 5px;
  }
```

```xml:boatPicker.js-meta.xml
<?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>61.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
```
ディプロイ後、忘れずに
ServiceアプリケーションのHomeに適当に配置しおく。

### エラー対応:

最初は下記のエラーが表示されるが、
新規でPlayground作成、LWCのAPIバージョンは61にしたらエラーが無くなっった。

:::note alert
In the boatPicker controller, we can’t find the proper configuration of which additional fields to search. 
:::