とあるSalesforce親方の日記

ちょっと長いことSalesforce開発やってます。

LWCの話題にかこつけて、すっかり忘れてたアイツ(Aura component)の話をする

※この記事はSalesforce 開発者向けブログ投稿キャンペーンへのエントリー記事です。

 

皆様こんにちは。親方です。

みんな、LWC書いてますかー!!!?

ぼくは、Visualforce書いてまーす!

だってClassicサポートしないといけないんだもん

去る6/25にTrailheaDX2020が開催されましたね!

午前0時過ぎから約6時間のナイトパーティーとはなんと粋なスケジュールだったことか(彼らは朝~昼の感覚です)

けど6/28現在、メンテで録画コンテンツが見れん!!!!?

これでは記事が書けん・・・

 

・・・てなわけで、あんま関係ないこと書きます。

Auraコンポーネントのこと、覚えてますか?

Lightning ExperienceのDev向け目玉コンテンツであったLightningコンポーネント、そのプログラミング基盤として「Aura」が採用されておりました。

これが主流になるから、という触れ込みだったのと上級Dev資格取得に必要だったのでTrailheadでコツコツ勉強しました。その頃にLEX開発やってた案件ではこれ使ったコンポーネントも作りましたよ。

今でもオープンソースだよ!停止してるけど

リファレンスはこちら

Lightning Aura コンポーネント開発者ガイド

そして2018年、Auraはおわりました。

Lightning Web Component(LWC)の登場によって、Auraはレガシーとなり、基盤のリポジトリも止まり、成長が止まりました。

けれども完全に息の根が止まったわけではありません。

コンポーネントライブラリには今でもAura向けのコンポーネントの掲載がありますし、跡形もなく消えたSコンと違って最新環境でもビルドできます。

 まだだ、まだ終わらんよ!

今回の記事は、そんな中途半端な時期にLightningコンポーネントを修得・実装していたAuraバトラー達の鎮魂のためになればと思い記述したものです。

昔こんなの作ってた

去年のLightning Championの活動の一環として、なんかサンプルコード書かねば・・・という危機感から作ったコードがあります。

カスタムJavascriptボタンがClassicでしか使えないため、Lightning Experience環境で代替できるものを作った感じです。

Aura1:①Contact新規作成アクション(<force:recordData>を使った初期値登録)

Aura2:②Account・Contact一括コピーアクション(Apexコントローラで一括取得・登録)

 

画面

<aura:component implements="force:hasRecordId,force:lightningQuickAction" access="global" >
    <aura:handler name="render" value="this" action="{!c.doInit}"/>
    <aura:attribute name="rec" type="Object"/>
    <aura:attribute name="recordInfo" type="Object"/>
    <aura:attribute name="recordId" type="String" />
    <aura:attribute name="recordLoadError" type="String"/>
    
    <!-- 起動時にレコード情報を読み込み -->
    <force:recordData aura:id="recordLoader"
        recordId="{!v.recordId}"
        fields="Name,Phone,Description,BillingCity,BillingStreet,BillingState,BillingPostalCode,BillingCountry"
        targetFields="{!v.rec}"
        targetError="{!v.recordLoadError}"
    />

</aura:component>

コントローラ

({
    //新規作成画面を呼び出し、force:recordDataで受信したレコード情報を初期値として差し込んで表示
    doInit : function(component, event, helper) {
        
        var createRecordEvent = $A.get("e.force:createRecord");
        
        /* 新規作成画面にパラメータを設定
         * entityApiName:対象オブジェクト
         * defaultFieldValues:初期値を差し込む項目
        */
        createRecordEvent.setParams({
            "entityApiName": "Contact",
            "defaultFieldValues":{
                "Phone":component.get("v.rec.Phone"),
                "Email":"test@testcompany.co.jp",
                "Description":component.get("v.rec.Description"),
                "MailingStreet":component.get("v.rec.BillingStreet"),
                "MailingCity":component.get("v.rec.BillingCity"),
                "MailingState":component.get("v.rec.BillingState"),
                "MailingPostalCode":component.get("v.rec.BillingPostalCode"),
                "MailingCountry":component.get("v.rec.BillingCountry"),
                "AccountId":component.get("v.recordId")
            }
        });
        
        //新規作成画面を表示
        createRecordEvent.fire();
        }
})

これをLWCで書くと

ちょうど良いサンプルコードとして、これをLWCに移植することを試みました。

以下の点に気をつけながら移植していきます。

 

画面

<template>
    <!-- 起動時にレコード情報を読み込み -->
    <div class="slds-p-top_large">
        <lightning-record-edit-form object-api-name={objectApiName}>
            <lightning-messages>
            </lightning-messages>
            <lightning-input-field field-name="AccountId">
            </lightning-input-field>
            <lightning-input-field field-name="Name">
            </lightning-input-field>
            <lightning-input-field field-name="Phone">
            </lightning-input-field>
            <lightning-input-field field-name="Description">
            </lightning-input-field>
            <lightning-input-field field-name="MailingStreet">
            </lightning-input-field>
            <lightning-input-field field-name="MailingCity">
            </lightning-input-field>
            <lightning-input-field field-name="MailingState">
            </lightning-input-field>
            <lightning-input-field field-name="MailingPostalCode">
            </lightning-input-field>
            <lightning-input-field field-name="MailingCountry">
            </lightning-input-field>
                <lightning-button
                    class="slds-m-top_small"
                    type="submit"
                    label="新規作成">
                </lightning-button>
        </lightning-record-edit-form>
    </div>
</template>

コントローラ

import { LightningElement, api, wire  } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import CONTACT_OBJECT from '@salesforce/schema/Contact';

const FIELDS = [
    'Account.Id',
    'Account.Name',
    'Account.Phone',
    'Account.Description',
    'Account.BillingCity',
    'Account.BillingStreet',
    'Account.BillingState',
    'Account.BillingPostalCode',
    'Account.BillingCountry',     
];

export default class LwcComp1 extends LightningElement {
    @api recordId;
    objectApiName = CONTACT_OBJECT;
    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    wiredRecord({ error, data }) {
        if (data) {
            console.log('success');
            console.log(data);
            
            this.AccountId = getFieldValue(data, 'Account.Id');
            this.Phone = getFieldValue(data, 'Account.Phone');
            this.Description = getFieldValue(data, 'Account.Description');
            this.MailingStreet = getFieldValue(data, 'Account.BillingStreet');
            this.MailingCity = getFieldValue(data, 'Account.BillingCity');
            this.MailingState = getFieldValue(data, 'Account.BillingState');
            this.MailingPostalCode = getFieldValue(data, 'Account.BillingPostalCode');
            this.MailingCountry = getFieldValue(data, 'Account.BillingCountry');
            
        } else if (error) {
            // Handle error. Details in error.message.
            console.log('error');
            console.log(error);
        }
    }

}

基本方針はわかった。しかし・・・

基本的に、AuraでできることはだいたいLWCでできます。

しかし、現行LWCの仕様ではできないことがあります。

Lightningレコードページから呼び出すアクションに指定できないんです。

今見たらやっぱりAuraで作ることになってました

これ今でもできないんでしたっけ・・・?

Lightning アクションは、既存の Lightning コンポーネントフレームワーク上に構築されます。既存の Aura コンポーネントを簡単にアクションに変換して、Salesforce モバイルアプリケーションや Lightning Experience で使用することができます。

Aura コンポーネントをアクションとして起動可能にするために、force:lightningQuickAction と force:lightningQuickActionWithoutHeader のいずれかのインターフェースをコンポーネントに追加します。

上述したforce:recordDataと同様に、force:XXXインターフェースはLWCには存在しないんです。

LWC時代にはどうやって作ればよいのでしょうか。

色々考えてみた

Auraコンポーネントの中にLWCを入れる

実は、AuraコンポーネントとLWCは入れ子構造にすることができます。

(常にAura側が親となる)

Lightning Web コンポーネントからの Aura コンポーネントの作成

一旦LWCを作った後、外枠としてAuraコンポーネントを作成し、そこにLWCを差し込むことでほぼLWCなAuraコンポーネントを作成することができます。

<aura:component implements="force:hasRecordId,force:lightningQuickAction">
    <c:lwcActionDetail name="LWC" />
</aura:component>
  • メリット:ほぼLWCで作れる
  • デメリット:形式上Auraは残る
Lightningフローを使う

Lightningコンポーネントと同様に、画面フローもまたアクションから呼び出すことができます。

(グローバルアクションを除く)

フローをうまく使えば数百件クラスの一括データ操作も可能ですし、いっそノンコーディングに置き換えるのも選択肢かと思います。

またTrailheaDXネタですが、Javascrpitを動かしたいのであれば"Salesforce Functions"も選択肢に含まれます。Salesforce Functionsはフローの中からサーバサイド処理として呼び出せるため、Lightningコンポーネントのコントローラを移植することができるのではないのでしょうか。

  • メリット:ノンコーディング開発できる
  • デメリット:UIの拡張性は今一つ、サーバサイド処理になる
Visualforceを使う

ええと、Lightning Championの立場からしたらお勧めしかねるのですが、ある意味最も堅実な選択肢です。

だってこれClassicでも動くんだもの!!

UIコンポーネントが充実しているLWCと異なり陳腐化したApexマークアップしか使えないVisualforceではありますが、自分でJavascriptフレームワークを導入すれば大した問題ではありません。

マークアップを極力使わず、Javascript主体で処理を行いApexもRemoteActionから呼ぶようにすればLightningコンポーネントと遜色ない処理はできてしまいます。

上のサンプルコードでも、Auraコンポーネント部分をVFに挿げ替えられるように作ってました。Apexクラスは簡単に共有化できますよ!

  • メリット:なんだかんだ好きに書けるので潰しが効く
  • デメリット:あるか?(Classic使わない人は覚えないでいいのでは)

あとがき

・・・てな感じで、画面作成のプラットフォームとしてはLWCが最先端で、Visualforceが根強く残り、Auraはその狭間でレガシーとして細々と存在している状態です。

今更習得するメリットは正直ほとんどないのですが、与太話として思い出して頂ければ幸いです。

さて、LWCの勉強せねば・・・