進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

コンポーネントとイベントの接続

学習の目的

この単元を完了すると、次のことができるようになります。
  • アプリケーションの‎カスタムイベントを定義する。
  • コンポーネントコントローラでイベントを作成して起動する。
  • 他のコンポーネントによって送信されるイベントをキャッチして処理するアクションハンドラを作成する。
  • 大きいコンポーネントを小さいコンポーネントにリファクタリングする。

コンポーネントとイベントの接続

この単元では、低コストアプリケーションの未完了機能について最後の部分 ([Reimbursed? (払い戻し済み?)] チェックボックス) に取り組みます。チェックボックスの実装のトピックは短くなるとお考えかもしれません。もちろん、簡便な方法を利用して非常に短いトピックにすることもできます。

しかし、この単元は、チェックボックスを機能させる方法に加えて、すでに利用した簡便な方法をすべて削除することについて説明します。この単元では、「適切に実施する」ことを説明します。つまり、少数ながら、すでに行ったリファクタリング作業を意味します。

それに取り組む前に、利用した簡便な方法、適切な方法、および適切な方法は若干困難だが優れている理由について最初に説明しましょう。

コンポジションと分解

小規模な Expenses アプリケーションをソースコード形式で確認し、別個のコードアイテムをリストする場合、次のようなものが思い付くでしょう。

  • expenses コンポーネント
    • expenses.cmp
    • expensesController.js
    • expensesHelper.js
  • expensesList コンポーネント
    • expensesList.cmp
  • expenseItem コンポーネント
    • expenseItem.cmp
  • ExpensesController (サーバ側)
    • ExpensesController.apex

以下のようにすべてが、後で結び付ける createExpense および updateExpense イベントによってまとめられます。

Expenses アプリケーションは、多くのより小さいコンポーネントで構成されます。

しかし、画面上のアプリケーションについて考えた場合、どのようなことが言えると思いますか。実現する必要があり、最終的にどこででも実現されることは、アプリケーションがさらに多数のコンポーネントに分解されることです。アプリケーションをさらに分解して、これまでよりも小さい要素にできることが分かります。少なくとも、経費追加フォームが実際に独自の別のコンポーネントであると確認できることを願っています。(そのため、ユーザインターフェースでフォームの周りにボックスを描画しました。)

そのフォームを別の‎コンポーネントにしなかったのはなぜか。それは、このモジュールのコースを引き継ぐ最も簡便な方法だからです。ソフトウェア設計の観点では、この方法は「いまいましい」と言われるハッカーよりも劣ります。Lightning コンポーネントアプリケーションを作成する適切な方法は、独立したコンポーネントを作成してから、一緒に構成して新しいより高いレベルの機能を構築することです。ではなぜこのアプローチを取らなかったのでしょう?

経費追加フォームにより、主要な expenses 配列コンポーネントの属性とその属性に影響を与えたコントローラコードが同じコンポーネント内に保持されるため、簡便な方法を利用し、経費追加フォームを主要な expenses コンポーネント内に保持しました。createExpense() ヘルパー関数で expenses 配列を直接操作できるようにしたかったのです。経費追加フォームを別のコンポーネントに移動した場合、それは不可能だったでしょう。

なぜでしょうか? 非常に早い段階で理由を簡単に説明しましたが、実際に説明しましょう。Lightning コンポーネントは自己完結型であることが求められます。これらは、すべての必須機能をカプセル化するスタンドアロン要素です。コンポーネントは、別のコンポーネントに (子コンポーネントにさえ) アクセスして内部を変更することはできません。

別のコンポーネントを操作するか影響を与える主要な方法が 2 つあります。1 つ目はすでにかなり目にしたり行ったりした方法で、コンポーネントのタグに属性を設定することです。コンポーネントの公開属性は API の一部分を構成します。

コンポーネントを操作する 2 つ目の方法はイベントを通じた方法です。属性と同様に、コンポーネントは送信するイベントと処理できるイベントを宣言します。属性と同様に、これらの公開イベントはコンポーネントの公開 API の一部分を構成します。すでにイベントを実際に使用し処理しましたが、イベントは一部の便利な機能の陰に隠れていました。この単元では、隠れていたイベントを表に出し、独自のイベントをいくつか作成します。

回路の配線について例え話をもう一度

これらの 2 つのメカニズム (属性とイベント) は API の「ソケット」 (コンポーネントを一緒に接続して完全な回路を形成する方法) です。また、イベントは陰ではその回路内を流れる電子になります。しかし、これはイベントが属性と異なるただ 1 つの点です。

<lightning:button>onclick 属性をコンポーネントのコントローラのアクションハンドラに設定したら、これら 2 つのコンポーネントの間に直接リレーションを作成します。それらはリンクされ、公開 API が使用され相互の独立が維持されている間でも連動します。

イベントは異なります。コンポーネントはイベントを別のコンポーネント送信しません。これはイベントの機能ではありません。コンポーネントは特定の種別のイベントをブロードキャストします。イベントの種別に対応するコンポーネントがあり、そのコンポーネントがイベントを「受信する」場合、イベントに基づいて動作します。

属性とイベントの違いは有線回路と線の違いと考えることができます。ここでは無線電話について説明しません。あるコンポーネントが別のコンポーネントの「番号」を取得してコールすることはありません。それは属性になります。イベントは無線放送と同様です。コンポーネントは無線で取得され、メッセージを送信します。外の誰が無線受信機を有効にして、適切な周波数に同調しましたか? コンポーネントがそれを知る方法がないため、コンポーネントによってブロードキャストされたイベントが受信されなくても OK になるようにコンポーネントを作成する必要があります(つまり、動作しない可能性がありますが何もクラッシュしません)。

コンポーネントからのイベントの送信

では、理論はここまでにし、アプリケーションを使用して具体的なことを行い、コード内のイベントのしくみを確認しましょう。まず、[Reimbursed? (払い戻し済み?)] チェックボックスを実装します。次に、その実装のために学習したことを行い、偉大なエンジニアが意図したとおり、使用して経費追加フォームを独自のコンポーネントにリファクタリングします。

最初に、<lightning:input>Reimbursed__c 項目のクリックハンドラを見てみましょう。

<lightning:input type="toggle"
            label="Reimbursed?"
            name="reimbursed"
            class="slds-p-around_small"
            checked="{!v.expense.Reimbursed__c}"
            messageToggleActive="Yes"
            messageToggleInactive="No"
            onchange="{!c.clickReimbursed}"/>

クリックハンドラの詳細に入る前に、<lightning:input> で提供されるものをおさらいしましょう。type="toggle" は、実際には切り替えスイッチデザインのチェックボックスです。class を使用すると、カスタム CSS スタイルの適用や SLDS ユーティリティの使用が可能になります。messageToggleActivemessageToggleInactive は、オン位置およびオフ位置に対するカスタム表示ラベルを提供します。<lightning:input> には、こうした便利な属性が他にも数多くあります。さらに、<lightning:input>onchange 属性を使用すると、切り替えスイッチが右 (オン) または左 (オフ) にスライドされたらレコードを更新するアクションハンドラに、スイッチを簡単に結び付けることができます。

次は、チェックボックスをオンまたはオフにした場合に生じることについて考えましょう。新しい経費を作成するために記述したコードに基づいて、経費の更新はおそらく次のようになります。

  1. 変更された expense 項目を取得します。
  2. 基礎となる経費レコードを更新する更新するサーバアクションを作成します。
  3. expense をアクションにパッケージ化します。
  4. 応答を処理するコールバックを‎設定します。
  5. アクションを起動し、要求をサーバに送信します。
  6. 応答が返され、コールバックが実行されたら、expenses 属性を更新します。

expenses 属性? コンポーネントのマークアップをもう一度確認しましょう。expenses はなく、単数形の expense のみです。このコンポーネントは 1 つの項目のためだけにあります。expensesList コンポーネントに expenses 属性がありますが、「実際の」expenses ではありません。実際の属性は、最上位 expenses コンポーネントのコンポーネント属性です。ん?

component.get("v.parent") がありますか? または、expenses を設定できるように、component.get("v.parent").get("v.parent") (親の親への参照を取得できるもの) にする必要がありますか?

ここで手を止めてください。

コンポーネントは他のコンポーネントにアクセスして値を設定することはできません。「やあ、おじいさん、expenses を更新しますね」と伝える方法はありません。コンポーネントは余計なことはしません。コンポーネントは上位コンポーネントで何かの変更を行う場合、イベントを適切に送信して依頼します

ここからがすばらしいところです。イベントの送信は、更新の直接処理とほぼ同じように見えます。次は clickReimbursed ハンドラのコードです。

({
    clickReimbursed: function(component, event, helper) {
        let expense = component.get("v.expense");
        let updateEvent = component.getEvent("updateExpense");
        updateEvent.setParams({ "expense": expense });
        updateEvent.fire();
    }
})

驚くべきことですね。ここまでは非常に簡単ですね。また、上記で想像したことのように見えます。clickReimbursed の前のコードは次を行います。

  1. 変更された expense を取得します。
  2. updateExpense という名前のイベントを作成します。
  3. expense をイベントにパッケージ化します。
  4. イベントを起動します。

コールバックのことはなくなりますが、それ以外は慣れていますね。しかし、何がサーバのコールと応答を処理し、主要な expenses 配列属性を更新するのでしょうか? また、この updateExpense イベントについてどうずれば分かるのでしょうか?

updateExpense はカスタムイベント (自分で記述するイベント) です。サーバアクションの取得と異なり、component.get() の代わりに component.getEvent() を使用するため、見分けられます。また、取得する内容には値プロバイダが含まれず、名前のみが含まれます。このイベントをすぐに定義します。

サーバのコールと応答を処理するものについて説明しましょう。ここで、expenseItem コンポーネントではサーバ要求を実装し、応答を処理できます。次に、イベントを送信して、expenses 配列に依存するものだけを再表示します。これは完全に有効な設計選択になり、expenseItem コンポーネントを完全な自己完結型に保持するため、望まれます。

ただし、やがてわかりますが、新しい経費を作成するコードと既存の経費を更新するコードは、コードの重複を避けたくなるほど非常に似ています。このため、行った設計選択は、主要な expenses コンポーネントによって処理される updateExpense イベントを送信することです。後でフォームをリファクタリングする場合、新しい経費の作成で同じことを行います。

サーバ要求を処理する責任と expenses 配列属性を管理する責任をすべての子コンポーネントに委譲すると、カプセル化が少し壊れます。しかし、これらの子コンポーネントを expenses コンポーネントの内部の実装詳細と考えれば問題ありません。主要な expenses コンポーネントは自己完結型です

重要なロジックの統合またはカプセル化を選択できます。ソフトウェア設計のトレードオフを行うのと同様に、Aura コンポーネントでトレードオフを行います。詳細をドキュメント化するようにします。

イベントの定義

最初に行うのは、カスタムイベントの定義です。開発者コンソールで [File (ファイル)] | [New (新規)] | [Lightning Event (Lightning イベント)] を選択し、イベントに「expensesItemUpdate」という名前を付けます。デフォルトのコンテンツを次のマークアップに置き換えます。

<aura:event type="COMPONENT">
    <aura:attribute name="expense" type="Expense__c"/>
</aura:event>

イベントの種別には、コンポーネントとアプリケーションの 2 つがあります。ここでは、上位コンポーネントでイベントをキャッチして処理するために、コンポーネントイベントを使用します。上位コンポーネントとは、コンポーネント階層でこのコンポーネントより上のコンポーネントのことです。任意のコンポーネントが受信できる「一般的なブロードキャスト」のようなイベントが必要な場合、アプリケーションイベントを代わりに使用します。

アプリケーションとコンポーネントイベントの違いおよび正しい使用法については、ここで網羅できるものではありません。高度なトピックであり、このモジュールの目的からそれてしまうほど複雑な詳細があります。詳細について学ぶ準備が整ったら、「リソース」が役立ちます。

イベントに関する他の注意事項は、定義がどれだけコンパクトかということです。イベントの作成時に expensesItemUpdate というイベント名を付けましたが、そのマークアップは、<aura:event> 開始/終了タグと 1 つの <aura:attribute> タグです。イベントの属性は実行できるペイロードについて説明します。clickReimbursed アクションハンドラで、setParams() へのコールを使用してペイロードを設定します。このイベント定義では、イベントパラメータを定義する方法と他に有効なパラメータがないことを確認します。

イベント定義のためのほとんどすべてのことを説明しました。実装や動作の詳細をイベント自体に追加しないでください。これらはパッケージにすぎません。実際、一部のイベントにはパラメータがまったくありません。これらはメッセージにすぎません。「これが発生しました」。「これ」が発生した場合に行うべきことに関するすべての動作は、イベントを送受信するコンポーネントに定義されています。

イベントの送信

clickReimbursed アクションハンドラで、実際のイベントの起動方法をすでに確認しました。ただし、これが機能するには、もう 1 つのこと (イベントの登録) を行う必要があます。次のマークアップの行を expenseItem コンポーネントの属性定義のすぐ下に追加します。

    <aura:registerEvent name="updateExpense" type="c:expensesItemUpdate"/>

このマークアップは、「c:expensesItemUpdate」という種別と「updateExpense」という名前を持つイベントをコンポーネントが起動することを示します。しかし、イベントの名前を定義した場合、名前は「expensesItemUpdate」ではないのでは? また、コンポーネントまたはアプリケーションのイベントの種別はどうなるのでしょう?

ちょっと紛らわしいと考えるのは当然です。実際のところ、若干ごまかしています。「アプリケーション」および「コンポーネント」を Aura コンポーネントフレームワークのイベント種別と考えると役立つ場合がありますが、定義するイベントの名前から取得される種別は、カスタムイベント種別 (イベント構造種別) です。つまり、イベントを定義する場合はパッケージ形式を定義します。イベントの送信を登録する場合、イベントが使用する形式を宣言します。

イベントの定義と登録のプロセスは、まだ少しおかしいと感じるかもしれませんので、もう少し先を見てみましょう。この expenseItem では、updateExpense という名前のイベントを送信します。expenseForm では、後で createExpense という名前のイベントを送信します。これらの両方のイベントには、サーバに保存する経費を含める必要があります。それで、両方とも c:expensesItemUpdate イベント種別またはパッケージ形式を使用してイベントを送信します。

受信側では、主要な expenses コンポーネントにより、これらの両方のイベントが処理されるように登録されます。サーバコールは最終的に同じになりますが、ユーザインターフェース更新は若干異なります。c:expensesItemUpdate パッケージで経費を作成するか更新するかを expenses はどのように知るのでしょうか? 送信されるイベントの名前で知ります。

この区別と、1 つのイベントを複数の目的に使用できる方法を理解すると、Lightning コンポーネントの学習でひらめきが生じます。ひらめいたという実感がまだないなら、残りのコードを見れば経験するでしょう。

イベント処理に進む前に、イベント送信に必要なことをまとめましょう。

  1. Lightning イベントを作成し、名前と属性を指定して、カスタムイベントを定義します。
  2. カスタムイベント種別を選択し、その種別の特定使用に名前を指定して、これらのイベントを送信するコンポーネントを登録します。
  3. 次を行い、コントローラ (またはヘルパー) のコードでイベントを起動します。
    1. component.getEvent() を使用した、特定のイベントインスタンスの作成。
    2. fire() を使用したイベントの送信。

先ほど確認したすべてのコードに進み実装した場合、コードを試行できます。アプリケーションを再読み込みし、[Reimbursed? (払い戻し済み?)] チェックボックスを数回切り替えます。ステップを飛ばした場合はエラーが表示されるので、作業を再確認する必要があります。すべて適切にできた場合、少し待てば、費用によって [Reimbursed? (払い戻し済み?)] の状況を示す色が予想どおりに変わります。

この動作はこの単元の開始前にも存在しました。これは、value="{!v.expense.Reimbursed__c}" が設定されている <lightning:input> コンポーネントの効果です。スイッチを切り替えると、ローカルバージョンの expense が更新されます。しかし、その変更はサーバまで送信されません。Salesforce で費用レコードを参照するか、アプリケーションを再読み込みした場合、変更が確認されません。

なぜでしょうか? イベントの完全な回路を作成する作業が半分だけ終了しました。もう一方のイベントハンドラを作成して、回路の配線を完了する必要があります。このイベントハンドラはサーバへの変更の送信と更新を永続的にすることを処理します。

イベントの処理

expenseItem コンポーネントを有効にしてイベントを送信するには 3 つのステップが必要でした。expenses コンポーネントを有効にして次のイベントを受信し処理するには 3 つの並行ステップが必要です。

  1. カスタムイベントを定義します。expenses が受信しているのと同じカスタムイベントを expenseItem が送信しているため、この作業を行っています。
  2. イベントを処理するコンポーネントを登録します。これにより、イベントがアクションハンドラに対応付けされます。
  3. アクションハンドラで実際にイベントを処理します。

ステップ 1 をすでに行っているので、すぐにステップ 2 を行い、updateExpense イベントを受信して処理する expenses を登録します。イベント送信のための登録と同様に、イベントを処理するための登録は 1 行のマークアップであり、init ハンドラの直後の expenses コンポーネントに追加する必要があります。

     <aura:handler name="updateExpense" event="c:expensesItemUpdate"
        action="{!c.handleUpdateExpense}"/>

init ハンドラと同様に、これは <aura:handler> タグを使用し、イベントにコントローラアクションハンドラを設定する action 属性があります。イベントを expenseItem に登録した場合と同様に、イベントの名前と種別を設定します。ただし、種別にはずっと実用的な名前の event 属性を使用します。

つまり、前に確認していない内容は、ここにはあまりありません。新機能と、カスタムイベントの処理に固有の機能は属性の組み合わせであり、expenses 内のこの受信者の「ソケット」が expenseItem 内の送信者の「ソケット」に一致する方法を認識しています。

これで、この作業の結び付けの部分が完了します。残りはアクションハンドラの実際の記述のみです。

handleUpdateExpense アクションハンドラから開始します。次はコードであり、clickCreate アクションハンドラのすぐ下に配置するようにしてください。

    handleUpdateExpense: function(component, event, helper) {
        let updatedExp = event.getParam("expense");
        helper.updateExpense(component, updatedExp);
    }

どうです? 面白いでしょう。フォーム検証チェックと、作業を委譲する固有のヘルパー関数を除いて、このアクションハンドラは handleCreateExpense と同じように見えます。

それでは、updateExpense ヘルパー関数を追加してみましょう。アクションハンドラを処理したように、このコードを createExpense ヘルパー関数のすぐ下に配置するようにします。

    updateExpense: function(component, expense) {
        let action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        action.setCallback(this, function(response){
            let state = response.getState();
            if (state === "SUCCESS") {
                // do nothing!
            }
        });
        $A.enqueueAction(action);
    },

すぐに気づくことが 2 つあります。まず、コールバックの詳細を除いて、updateExpense ヘルパーメソッドは createExpense ヘルパーメソッドと同一です。リファクタリングできる可能性があります。

2 つ目は、これらのコールバックの詳細についてです。どうなっているのでしょうか? どのようにすれば、やるべきことをなしにできるのでしょうか?

少しの間考えてみてください。以前、イベント送信をテストする場合 (前にテストしていない場合)、expenseItem コンポーネントの色が [Reimbursed? (払い戻し済み?)] チェックボックスの切り替えに応じて変化することを確認しました。説明を覚えていますか? 経費レコードのローカルコピーはすでに更新されています。そのため、バージョン更新に成功したことがサーバから通知された場合、少なくともしばらくは何もする必要はありません。

このコードはサーバが経費レコードの更新に成功した場合のみに対処します。もちろん、エラーがあった場合に行う一部の作業はあります。この経費を経理が払い戻し不可としてフラグ設定したとすると、この項目を true に設定することはできなくなります。ただし、これはいわゆる別の日のレッスンになります。

ヘルパー関数のリファクタリング

特定の共通コードをくくり出すために見つけた機会に戻りましょう。2 つのヘルパー関数は callback を除いて同一です。そのため、callback をパラメータとして取る新しい一般化された関数を作成しましょう。

    saveExpense: function(component, expense, callback) {
        let action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        if (callback) {
            action.setCallback(this, callback);
        }
        $A.enqueueAction(action);
    },

callback パラメータは省略可能です。そこにある場合は、action に渡します。簡単です。イベント固有のヘルパー関数を減らして次のコードにすることができます。

    createExpense: function(component, expense) {
        this.saveExpense(component, expense, function(response){
            let state = response.getState();
            if (state === "SUCCESS") {
                let expenses = component.get("v.expenses");
                expenses.push(response.getReturnValue());
                component.set("v.expenses", expenses);
            }
        });
    },
    updateExpense: function(component, expense) {
        this.saveExpense(component, expense);
    },

createExpense は少し短くなっただけですが、応答が返された (コールバック) 場合に対処方法のみに焦点が絞られました。また、updateExpense が 1 行になりました。

経費追加フォームのリファクタリング

このような小さなリファクタリングの練習問題は満足感が大きく、イベントの使用ではとても興奮してしまいました。もう一度、ただし、大きい追加の改善をやってみましょう。

次の作業には、expenses コンポーネントからの経費追加フォームの抽出と、独自の新しいコンポーネントへの移動が含まれます。フォームのマークアップの抽出は、とても簡単で単純なコピー/貼り付けの練習問題です。他に一緒に移動するものは何でしょうか? 行き当たりばったりであちこちに移動することを始める前に、移動するものと残すものについて検討しましょう。

現在の設計では、フォームのアクションハンドラ (clickCreate) は入力規則を処理し、要求をサーバに送信して、ローカルの状態とユーザインターフェース要素を更新します。フォームは引き続きアクションハンドラが必要であり、おそらくフォーム検証を処理する必要もあります。しかし、サーバ要求のロジックを expenses コンポーネント内に統合した状態にするために、残りをそのままにすることを計画します。

そのため、少し (ただし少しだけ) 分離してそこで実行します。計画はフォームのマークアップの移動から開始し、その後はほんの少しだけ移動して正しく動作するようにします。expenses 配列のコンポーネント属性への直接アクセスによってではなく、イベントによって通信するように 2 つのコンポーネントをリファクタリングします。

それでは始めましょう。

expenses メインコンポーネントで、2 つの <!-- CREATE NEW EXPENSE --> コメントの間にある内容を開始コメントと終了コメント自体を含めてすべて選択します。それをクリップボードに切り取ります(そうです、切り取るのです。まじめな話です)。

新しい Aura コンポーネントを作成し、「expenseForm」という名前を付けます。コピーした [Add Expense (経費を追加)] フォームのマークアップを新しいコンポーネントの <aura:component> タグの間に貼り付けます。

expenses コンポーネントに戻ります。新しい expenseForm コンポーネントをマークアップに追加します。expenses のそのセクションは次のようになります。

    <!-- NEW EXPENSE FORM -->
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:expenseForm/>
        </lightning:layoutItem>
    </lightning:layout>

この時点でアプリケーションを再読み込みして変更を確認できます。目に見える変化がないようにしてください。ただし、当然ですが、[Create Expense (経費を作成)] ボタンが動作しなくなります。

あちこちに移動する部分の残りをすぐに済ませましょう。

次に、newExpense 属性を expenses コンポーネントから expenseForm コンポーネントのマークアップに移動します。これはフォーム項目に使用されるため、フォームコンポーネント内にある必要があります。移動には変更が必要ないため、ある場所から切り取って別の場所に貼り付けるだけです。

expenseForm コンポーネントで、コントローラとヘルパーリソースを作成します。

clickCreate アクションハンドラを expenses コントローラから expenseForm コントローラに移動します。このボタンはフォームコンポーネント内にあるため、ボタンのアクションハンドラはそこにもある必要があります。信じられないかもしれませんが、ここでも変更は不要です(そろそろここのテーマにお気づきでしょうか)。

次に、いくつかの変更を実際に行う必要があります。しかし、次は見慣れているでしょう。expenseItem. expenseItem に対して前に行ったイベント送信の追加のみを行うため、イベントを取り消して、expenses コンポーネントで処理される expense ペイロードでイベントの送信も行います。

expenseForm ヘルパーで、createExpense 関数を作成します。

    createExpense: function(component, newExpense) {
        let createEvent = component.getEvent("createExpense");
        createEvent.setParams({ "expense": newExpense });
        createEvent.fire();
    },

これは、expenseItemclickReimbursed アクションハンドラに非常によく似ています。

コンポーネントがイベントを送信する場合、イベントを登録する必要があります。expenseForm コンポーネントマークアップの newExpense 属性のすぐ下に次を追加します。

    <aura:registerEvent name="createExpense" type="c:expensesItemUpdate"/>

この時点で、expenseForm コンポーネントを実装するすべての作業が完了しました。アプリケーションを再読み込みでき、エラーがないという意味でフォームが「動作」するようになり、無効なデータを入力すると適切なフォームメッセージが表示されます。Salesforce Lightning Inspector を使用すると、expensesItemUpdate イベントが起動中であることも表示できます。残りは処理のみです。

イベントを処理する前に、このリファクタリングがいかに簡単だったかに気づいてください。ほとんどのコードは変更していません。合計 6 行の新しいコードとマークアップを前のステップで変更しました。本日のこのような作業は見慣れていないかもしれませんが、数回実行してください。少しのコードをあちこち移動しているだけであることに気づきます。

では、完了させましょう。expenseFormcreateExpense イベントを起動しますが、expenses コンポーネントがそのイベントをキャッチする必要もあります。まず、createExpense イベントハンドラを登録し、handleCreateExpense アクションハンドラに結び付けます。次は、ここでも 1 行のマークアップになります。この行を updateExpense イベントハンドラのすぐ上か下に追加します。

    <aura:handler name="createExpense" event="c:expensesItemUpdate"
        action="{!c.handleCreateExpense}"/>

ついに最後のステップで、expenses コントローラの handleCreateExpense アクションハンドラを作成します。このコードを handleUpdateExpense イベントハンドラのすぐ上か下に追加します。

    handleCreateExpense: function(component, event, helper) {
        let newExpense = event.getParam("expense");
        helper.createExpense(component, newExpense);
    },

簡単ですよ。すべての作業は createExpense ヘルパー関数に委譲され、移動や変更が行われませんでした。handleCreateExpense アクションハンドラは適切なものを一緒に結び付けるためだけにそこにあります。

これで、イベントを使用するコンポーネントを疎結合にする方法を示しました。ワイヤレス回路において、あるコンポーネントでイベントを作成して起動し、別のコンポーネントでそのイベントをキャッチして処理します。

‎ボーナスレッスン - 軽微な視覚的改善

課題に取り組む前に、軽微で視覚的な改善を次に示します。

いくつかコンテナコンポーネントを追加して、アプリケーションのレイアウトを少し改善します。この最後のビットは、すべての変更の後に完全な expense コンポーネントを表示する機会も提供します。expense コンポーネントで、expensesList マークアップを次のマークアップで置き換えます。

<lightning:layout>
    <lightning:layoutItem padding="around-small" size="6">
        <c:expensesList expenses="{!v.expenses}"/>
    </lightning:layoutItem>
    <lightning:layoutItem padding="around-small" size="6">
        Put something cool here
    </lightning:layoutItem>
</lightning:layout>

変更により、一部の余白とパディングを追加し、費用リストを絞り込むことができます。このレイアウトで、右の上に何かを置く余裕ができます。次の単元では、自分で行うことができるいくつかの練習問題を提示します。