背景
画像はTrailheadから拝借...
View-Controller-Controller-databaseモデル
- Aura Componentのモデル図は下記のようになっていたことを再度認識する
これまで作成していたもの
1. Create
ボタンがクリックされれば、Controller(Javascript)がcallされる
2. Controller(Javascript)側からView(Component)の要素を取得
3. Controller(Javascript)側からView(Component)に値をセット
これから作成するもの: サーバー側 Controller(Apex)も使用する
1. Create
ボタンがクリックされれば、Controller(Javascript)がcallされる
2. Controller(Javascript)側からView(Component)の要素を取得
3. Controller(Javascript)側からController(Apex)のCallBack
関数の呼び出し
4. Controller(Javascript)側からController(Apex)関数の呼び出し
5. Controller(Apex)側で処理を実行
6. Controller(Apex)側でCallBack
処理を実行し、View(Component)に値をセット
- 重要なポイント
手順5の処理を待たずにクライアント側を動かすために、非同期処理が行われる。
そのためのCallBack
関数。サーバー側の処理が終わってからCallBack
処理を実施することで、クライアント側からサーバーの処理が終わるまで待機する必要がなくなる。
Controller (Apex) の作法
public with sharing class ExpensesController { // STERN LECTURE ABOUT WHAT'S MISSING HERE COMING SOON @AuraEnabled public static List<Expense__c> getExpenses() { return [SELECT Id, Name, Amount__c, Client__c, Date__c, Reimbursed__c, CreatedDate FROM Expense__c]; } @AuraEnabled public static Expense__c saveExpense(Expense__c expense) { // Perform isUpdateable() checking first, then upsert expense; return expense; } }
- AuraコンポーネントからApex関数を呼び出す場合は
@AuraEnabled
を記述する - メソッドは
static
を記載し、publicまたはglobalで適用されるように定義する - セキュリティの観点から、
public with sharing class
でメソッドを定義する- これを使用することにより、このメソッドで使用できるレコードに組織の共有ルールが自動的に適用される
セキュリティ対策を最小限に行なったApex Method例
@AuraEnabled public static List<Expense__c> getExpenses() { // Check to make sure all fields are accessible to this user String[] fieldsToCheck = new String[] { 'Id', 'Name', 'Amount__c', 'Client__c', 'Date__c', 'Reimbursed__c', 'CreatedDate' }; Map<String,Schema.SObjectField> fieldDescribeTokens = Schema.SObjectType.Expense__c.fields.getMap(); for(String field : fieldsToCheck) { if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) { throw new System.NoAccessException(); } } // OK, they're cool, let 'em through return [SELECT Id, Name, Amount__c, Client__c, Date__c, Reimbursed__c, CreatedDate FROM Expense__c]; }
- 概要レベルで説明すると、ユーザが参照/変更対象のレコードにアクセス権があるかどうか確認する
getDescribe()
メソッドはコストが高くなるため頻繁に使用するのはやめた方が良い
Aura Component側の作法
<aura:component controller="ExpensesController"> <aura:attribute name="foo"/> ... <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
- Apexクラスの名前を上記のように記載することで、Component/Apex間の関連を示す
- アクションハンドラを指定してコンポーネントが読み込まれた場合にController(Javascript)をcallする
Controller(Javascript)側の作法
// Load expenses from Salesforce doInit: function(component, event, helper) { // Create the action let action = component.get("c.getExpenses"); // Add callback behavior for when response is received action.setCallback(this, function(response) { let state = response.getState(); if (state === "SUCCESS") { component.set("v.expenses", response.getReturnValue()); } else { console.log("Failed with state: " + state); } }); // Send action off to be executed $A.enqueueAction(action); }, })
- 関連付けされたApexのメソッド(
@AuraEnabled
)を呼び出すのは、下記
// Create the action let action = component.get("c.getExpenses");
$A.enqueueAction(action);
によってサーバー要求をキューに登録する。- コントローラーアクションはこの行で終了となる。
- いつ戻ってくるのか、または戻ってくるのかは不明(え?)
component.set("v.expenses", response.getReturnValue());
のgetReturnValue()
で返却される型について- Apex側の定義:
public static List<Expense__c> getExpenses() {
- Component側の定義:
<aura:attribute name="expenses" type="Expense__c[]"/>
- 上記のように型が一致している場合は特に考慮不要。
- Apex側の定義:
({ createExpense: 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") { let expenses = component.get("v.expenses"); expenses.push(response.getReturnValue()); component.set("v.expenses", expenses); } }); $A.enqueueAction(action); }, })
action.setParams
が重要。パラメータ名: パラメータ値で定義する.- ここでの
パラメータ名
はApex側の引数名と合わせておく必要がある。 - 参考
public static Expense__c saveExpense(Expense__c expense) {
- ここでの
値プロパイダについて
識別子 | コンテキスト | 意味 |
---|---|---|
c. | コンポーネントのマークアップ | クライアント側コントローラ |
c. | コントローラコード | サーバ側コントローラ |
c. | マークアップ | デフォルトの名前空間 |
Challenge
上記を理解していれば今回は難しくない.