' P '

whatever I will forget

LWC superbadgeでのメモ

import関連

Apexを読み込む際

import メソッド名 from '@salesforce/apex/Apexクラス名.メソッド名

import getBoatTypes from '@salesforce/apex/BoatDataService.getBoatTypes';

wire, track, api

import { LightningElement, wire } from 'lwc';

参考:
[LWC] 変数宣言時のデコレータ (@api, @track, @wire) | Salesforceのはじめ

wire

  • @wire は、組織からデータを取得できるデコレータ.
  • コンポーネントが読み込まれた場合に処理される
    • ボタンなどの処理によってイベント的に、故意にApexを呼び出したい場合はImperative Apexを検討する
  • @wireを使ってメソッドを呼び出す場合は下記の文法となる.
@wire(getRecord, { recordId: '$recordId', fields: FIELDS })
wiredMethodName({error, data}) {
  if(error) {
    // error logic
  } else if(data) {
    // expected logic
  }
}
  • apex classを呼び出す場合は、Apex側の引数(param1)とJs側の変数(val1)を下記のように記載.
@wire(someApexMethod, { param1: '$val1', param2: '$val2' })
wiredMethod({error, data}) {
  // ...
}

参考: Wire Apex Methods to Lightning Web Components

※ Imperative apexの場合は someApexMethod({ param1: val1, param2: val2 })でcallする。
Call Apex Methods Imperatively

getFieldValue

  • wireで取得した後に値を取得する標準関数
  • 参考: getFieldValue
  • 引数はレコードと項目名
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

import { LightningElement, api, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
import CREATED_FIELD from '@salesforce/schema/Account.CreatedDate';
import EXP_FIELD from '@salesforce/schema/Account.SLAExpirationDate__c';

const fields = [REVENUE_FIELD, CREATED_FIELD, EXP_FIELD];

export default class WireGetValue extends LightningElement {
    @api recordId;

    @wire(getRecord, { recordId: '$recordId', fields })
    account;

    get revenue() {
        return getFieldValue(this.account.data, REVENUE_FIELD);
    }
    // ...
}

track

子要素のみを変更した際に値を再描画させるデコレータ
ちなみに@trackは特に指定しなくても良くなったっぽい(Summer'20から)
Lightning Web コンポーネントで不要になった @track デコレータ

api

@api を用いると、外部に変数や関数を公開するデコレータ.
要はデコレートした変数をpublic扱いにして、他コンポーネントからも参照・変更を可能にすることが可能.
基本的には親コンポーネントから子コンポーネントへの値の受け渡しで使われる.

refreshApex

  • cacheable=trueになっているApexメソッド、かつLWCから呼び出した際にキャッシュクリアさせる場合に使用
  • importして、キャッシュされている変数に対して実行
import { refreshApex} from '@salesforce/apex';
await refreshApex(this.data);

参考: Client-Side Caching of Apex Method Results

async/await

  • 非同期でLWCからApexを実行させる場合
import ApexMethod1 from '@salesforce/apex/ApexClass.ApexMethod1';
import ApexMethod2 from '@salesforce/apex/ApexClass.ApexMethod2';
import ApexMethod3 from '@salesforce/apex/ApexClass.ApexMethod3';

async handleOKClick(event) {
   // Apexクラスのメソッドを呼び出す
   const result1 = await ApexMethod1({param: 1});
   const result2 = await ApexMethod2({param: 2});
   const result3 = await ApexMethod3({param: 3})
}

静的リソースを読み込む際

import myResource from '@salesforce/resourceUrl/resourceReference';

  • resourceReferenceがアップロードしたファイル名.

静的リソースにJavascriptcssがある場合

参考: Platform Resource Loader

  • loadScript()loadStyle()という関数が用意されている.
    • ちなみに返却されるのはそれぞれPromiseになる.
  • 例えば上記の通り、myResourceをimportした場合の例.
import { loadStyle, loadScript } from 'lightning/platformResourceLoader';

// ...

    Promise.all([
      loadScript(this, myResource + '/sample.js'),
      loadStyle(this, myResource + '/sample.css')      
    ]).then(() => {
      // logic
    })
    .catch(error => {
      const toast = new ShowToastEvent({
          title: ERROR_TITLE,
          message: error.message,
          variant: ERROR_VARIANT,
      });
      this.dispatchEvent(toast);
    });
  }

カスタム表示ラベル

import labelSample from '@salesforce/label/c.Sample';

SLDS (HTML)

combobox

developer.salesforce.com

HTMLに記述する例:
- value : 選択された値
- options : 選択できる値
- onchange : Jsに発火するイベント

<template>
    <lightning-combobox
            name="progress"
            label="Status"
            value={value}
            placeholder="Select Progress"
            options={options}
            onchange={handleChange} ></lightning-combobox>

    <p>Selected value is: {value}</p>
</template>

選択された値は下記で取得

    handleChange(event) {
        this.value = event.detail.value;
    }

Formatted Number

  • 小数点の桁数を指定.
    <p><lightning-formatted-number value="1234.5678" maximum-fraction-digits="2"></lightning-formatted-number></p>

spinner

  • いわゆるクルクルのLoadingアイコン.
  • Spinner
<div class="exampleHolder">
        <lightning:spinner alternativeText="Loading" size="small" />
</div>

Tabset

  • LWC上のタブを生成する
  • variantを指定することが可能で、scopedに指定した場合デザインが変わる
  • 標準
  • Scoped
<template>
    <lightning-tabset variant="scoped">
        <lightning-tab label="Item One">
            One Content !
        </lightning-tab>
        <lightning-tab label="Item Two" title="2nd tab extended title">
            Two Content !
        </lightning-tab>
        <lightning-tab label="Item Three">
            Three Content !
        </lightning-tab>
    </lightning-tabset>
</template>

参考: lightning-tabset

Datatable

  • データテーブルを作成する
  • 保存時にJavaScriptへのアクションを行いたい際は onsave={functionName}としておく
  • インライン編集を有効化したい場合はcolumnで指定した値にeditable : 'true'を指定し draft-values={draftValues}を指定
const columns = [
    { label: 'Name', fieldName: 'Name', editable: true },
    { label: 'Description', fieldName: 'Description__c'},        
  ];
<lightning-datatable key-field="Id" data={data} columns={columns} draft-values={draftValues} onsave={handleSave} hide-checkbox-column></lightning-datatable>

詳しいやり方はこちら: Display Data in a Table with Inline Editing
仕様についてはこちらWorking with Inline Editing章を確認

lightning card / button & slot

slotとかいうのがいきなりでてきたのでよくわからずだったのですが.
lightning-cardの中でbuttonを使用する際に slot="actions"と指定するとボタンがタイトルの反対側に配置されるようです.
これはplaygroundでやってみたらわかりやすいかと.

<lightning-card  title="Hello">
  <lightning-button label="New" slot="actions"></lightning-button>
  <p class="slds-p-horizontal_small">Card Body (custom component)</p>
  <p slot="footer">Card Footer</p>
</lightning-card>

参考: lightning-card
参考: lightning-button

<lightning-button label="Submit" type="submit" icon-name="utility:save"></lightning-button>

ページの遷移

ページの遷移はURLを直接指定ではなく、NavigationMixinを使用してURL生成や遷移を行うようです.
navigation
例えば、レコードページに遷移させる場合は下記:
optionはviewnewhomeなどがあるっぽい.

<lightning-card title="Test">
  <lightning-button label="Test" onclick={createNewData} slot="actions"></lightning-button>
</lightning-card>
import { NavigationMixin } from 'lightning/navigation';

export default class MyCustomElement extends NavigationMixin(LightningElement) {
  // logic
  createNewData() { 
    this[NavigationMixin.Navigate] ({
      type: 'standard__objectPage',
        attributes: {
          objectApiName: 'Data__c',
          actionName: 'view'
        },  
    });
  }
}

参考: Basic Navigation

qiita.com

あるレコードの値をリンクにしたい場合

  • HTML側からdata-record-id属性でリンクしたいレコードを指定
  • JavaScript側でevent.target.dataset.recordIdを指定してHTML側から指定された値を取得する
<a title="Test" onclick={navigateToRecord} data-record-id={Data.CreatedBy.Id}>
navigateToRecord(event) {  
    this[NavigationMixin.Navigate] ({
        type: 'standard__ recordPage',
        attributes: {
            recordId: event.target.dataset.recordId,
            objectApiName: 'User',
            actionName: 'view'
        },  
    });
}

公式のやり方は見つからず...

salesforce.stackexchange.com

Record View Form

いつもレコードを見ているあのデザインをサクッと
参考: Record View Form

  <lightning-record-view-form record-id={recordId} object-api-name={objectApiName} density="compact">
        <template if:true={showFields}>
            <lightning-output-field field-name="Name"></lightning-output-field>
            <lightning-output-field field-name="Industry"></lightning-output-field>
        </template>
    </lightning-record-view-form>

Record Edit Form

参考: Record Edit Form

  • lightning-record-edit-formはFormを描画し、例えばボタンでレコードのsubmitを行う場合はlightning-buttonのtype="submit" とすること
  • defaultではsubmitはonclickで行うが、その処理をカスタマイズすることも可能
    • 上記のOverriding Default Behaviors章を参照
    • onsubmitにて、handleSubmitを行い、デフォルトのsubmitをevent.preventDefault();で防止している
    • onsucessにて、handleSucess内でレコードの変更を処理
handleSubmit(event){
   event.preventDefault();       // stop the form from submitting
   const fields = event.detail.fields;
   fields.Street = '32 Prince Street';
   this.template.querySelector('lightning-record-edit-form').submit(fields);
}
handleSucess(event){
   const updatedRecord = event.detail.id;
   console.log('onsuccess: ', updatedRecord);
}
  • formのリセットは下記の通りで, lightning-input-fieldに対して値を取得してresetする
handleReset(event) {
   const inputFields = this.template.querySelectorAll('lightning-input-field');
   if (inputFields) {
       inputFields.forEach(field => {
           field.reset();
       });
   }
}

Form

参考: Form Elements
- Formエレメントは、slds-form-elementによって初期化される
- 3つの要素で構成される; - label slds-form-element__label
- form control container slds-form-element__control
- form input element, i.e.

Input Field

参考: lightning-input-field

<div class="slds-form-element">
  <label class="slds-form-element__label" for="account">Test</label>
    <div class="slds-form-element__control">
      <lightning-input-field field-name="account" variant="label-hidden" required></lightning-input-field>
  </div>
</div>

スクロール

要素をスクロールさせたい時。Auto、x軸(横スクロール)、y軸(縦スクロール)が存在する

<div class="slds-scrollable_y" style="height:5rem;width:24rem">

www.lightningdesignsystem.com

要素を真ん中に

<div class="slds-align_absolute-center" style="height:5rem">This content will be positioned in the absolute center of its container</div>

www.lightningdesignsystem.com

Lightning Layout Item

  • これをやりたい場合
  • レコードを表示させたい場合は、keyattributeにレコードIdを渡す。
<lightning-layout-item key={data.Id} padding="around-small" size="12" small-device-size="6" medium-device-size="4" large-device-size="4">

参考: Layout Item


Javascript

カスタムイベントの作成

www.hypertextcandy.com

  • detailのプロパティ名はきまっているらしい
// カスタムイベントの作成
const event = new CustomEvent('eventname', { detail: 'Hello world' });

// カスタムイベントをListenする
elem.addEventListener('eventname', function(e) {
  console.log(e.detail);
});

// カスタムイベントを発行する
elem.dispatchEvent(event); // -> 'Hello world'

ブラウザから位置情報を取得する

if( navigator.geolocation ) {
 //
}
  • navigator.geolocation.getCurrentPosition()を使用する。引数は3つで必須は1つ。成功時に何をするのかの関数.
  • 成功した場合のデータは指定した関数名.coordsに格納されている。
    • 例えばposition.coords.latitude.
    if(navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(postion => {
            this.latitude = position.coords.latitude;
            this.longitude = position.coords.longitude;
        });
    }

unshift関数

arrayの先頭に要素を追加する.

www.htmq.com


LWC

要素のループ

  • JavaScipt側の変数名を指定
    • 例だとJavaSciprt側にvals変数が存在
  • <template>にLoop文法を記述
<template for:each={vals} for:item="val">

参考: Render Lists

HTML側での条件分岐

<template if:true={isLoading}>
  <lightning-spinner alternative-text="Loading" variant="brand" size="large"></lightning-spinner>
</template>

LWCの背景を画像にする

<template>
  <div style={backgroundStyle}>
  </div>
</template>
import { LightningElement } from 'lwc';
import backgroundUrl from '@salesforce/resourceUrl/background';

export default class Poc extends LightningElement {
    get backgroundStyle() {
        return `background-image:url(${backgroundUrl})`;
    }
}

Component同士の通信

Component Namespace

  • コンポーネントを参照する際に、いくつかルールがあるようなのでメモ
    参考: Component Folder
  • component名はキャメルケースを使用する
  • 参照する際はキャメルケースで区切られた名前を-で区切る
    例: myComponent.htmlがある場合
<c-my-component></c-my-component>

Custom Event

  • 基本的には 子 → 親にイベントを飛ばしたいときに行う
    JavaScriptだとListenerを明記するが、LWCの場合は下記となる
        const customEventTest = new CustomEvent('customeventtest', {
            detail: {dataId: this.selectetDataId}
        });
  • 上記の子側JavaScriptで明記されたイベント名 'customeventtest'に対して、親側のhtml側で on + イベント名とする
<c-custom-event-created oncustomeventtest={eventHandle}></c-custom-event-created
eventHandle(event) {
  this.data = event.detail;
}

詳しくは下記(めっちゃわかりやすい)

qiita.com

参考(英語):

www.apexhours.com

参考(公式): Create and Dispatch Events

@api (親コンポーネント → 子コンポーネントの通信)

  • @apiを使う.
  • public propertyにする方法と、public methodにする方法がある.

public property

  • 子側のJavaScript@apiでデコレータされた値が myVariableだった場合
  • かつ子側のコンポーネント名がmyCoponent.htmlだった場合
    • 親側での参照は下記のようになる
<c-my-component my-variable="Test"></c-my-component>

参考: Set Properties on Child Components

public method

this.template.querySelector('c-video-player').play();

※ちなみに、public (@api) のgetter/setterを呼び出す場合は普通にmethod名をそのままコールできるよう.

<c-sample getter-name={data}></c-sample>

Lightning Message Service

  • LWC/Aura/Visualforce間でのPublish <-> Subscribeでの通信が可能となる.

qiita.com

www.apexhours.com

Lightning message channelを作成

import channelName from '@salesforce/messageChannel/channelReference';
  • channelNameは任意.
  • channelReferenceは作成したxmlファイルの名前 + __c.

Subscribeする

  • @wireでMessege ServiceのmessageContextを初期化する.
@wire(MessageContext)
messageContext;
subscribeToMessageChannel() {
    if (!this.subscription) {
        this.subscription = subscribe(
            this.messageContext,
            channelName,
            (message) => {this.dataId = message.recordId},
            { scope: APPLICATION_SCOPE }
        );
    }
}

// Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel
    connectedCallback() {
        this.subscribeToMessageChannel();
    }

publishする

  • publishメソッドは3つの引数
    messageContext, Message Service, Message
    const payload = {recordId: dataId};
    publish(this.messageContext, MC, payload);

Message Service

ToastMessage (UIにメッセージを表示)

import {ShowToastEvent} from 'lightning/platformShowToastEvent';
// ...
const event = new ShowToastEvent({
  title: ERROR_TITLE,
  message: error.message,
  variant: ERROR_VARIANT
});
this.dispatchEvent(event);

Lightning Map & MapMarkers

Lightning Map

  • makerに値をセット.
<template>
    <lightning-map map-markers={mapMarkers}> </lightning-map>
</template>
import { LightningElement } from 'lwc';

export default class LightningMapExample extends LightningElement {
    mapMarkers = [
        {
            location: {
                Latitude: '37.790197',
                Longitude: '-122.396879',
            },
        },
    ];
}

getterとsetter

参考: Use Getters and Setters to Modify Data

  • 関数名の最初に getsetを付けることを忘れずに!
  get sampleGetter() {
    return this.data ? "Yes" : "No";
  }
  set itemName(value) {
       this.data = true;
   }
  • publicなSetterを作成する場合は、getterも必ず作成する必要がある
  • その場合、どちらかのmethodを@apiデコレーションはしておくこと

metaデータ関連

Configuration タグ

  • 重要なのは:
    • isExposed : これをTrueにしないとApp / Experience Builderに表示されない
    • targets/target : これでそのコンポーネントをどこに表示させるか指定
    • property : App BuilderやFlow Builderなどで配置/使用する際に選択できる入力値を設定
    • objects/object : コンポーネントが使用可能なオブジェクトを制限する

XML Configuration File Elements