Salesforce Platform Developer I：Aura コンポーネントの基本

# Auraコンポーネントの基本
https://trailhead.salesforce.com/ja/content/learn/modules/lex_dev_lc_basics

<font color="red">**「私のドメイン」は、Lightning コンポーネントを使用した開発に必要です**</font>
　トライアル組織には：デフォルトで[私のドメイン]が用意されています。
　本番：「設定」>「私のドメイン」設定必要

## 事前準備
カスタムオブジェクト作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/c66b5646-b1fb-ff26-28fe-d399739e55fd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/494a5d08-604d-1244-ecb6-ecec9d2a32d9.png)
Plural Label変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/8da34bde-621f-f58a-befd-253697068a53.png)

## Aura コンポーネントの使用開始
Lightningコンポーネントフレームワーク：モバイルデバイス用とデスクトップデバイス用の Webアプリケーションを開発するUIフレームワークです。

SLDS：Salesforce Lightning Design System

MVCC(ビュー（.cmp）-クライアントコントローラ（controller.js,help.js）-サーバのコントローラ（apex）-データベース（object）)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/74587db9-7273-e6d9-5eea-0466df403467.png)

cmpの利用できるタグ
<<aura:XXXX>>、<<lightning:XXXX>>、<<force:XXXX>>また<<ui:XXXX>>（uiタグがお勧めではない、サポートされないタグが多くになる）

### Auraコンポーネント作成
**● helloWorld** — コンポーネントバンドル
　**○ helloWorld.cmp** — Component :コンポーネントの定義（HTMLをベースにLightningタグをマークアップ）
　**○ helloWorldController.js** — Controller :コンポーネントのコントローラ (メインJavaScript ファイル、JavaScriptでアクションを記述)
　**○ helloWorldHelper.js** — Helper :コンポーネントのヘルパー (セカンダリJavaScript ファイル、JavaScriptで横断的なビジネスロジックを記述)
　**○ helloWorld.css** — Style: コンポーネントのCSSを定義
　**○ helloWorld.auradoc** — Documentation :コンポーネントの使用方法を定義
　**○ RhelloWorldRenderer.js** — renderer :レンダリングフェーズにおける特殊な挙動を定義
　**○ helloWorld.design** — Design :アプリケーションビルダーでの設定項目を定義
　**○ helloWorld.svg** — SVG :アプリケーションビルダー上のアイコンを定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/b663ef85-ae4a-3a5f-f5c7-1160f4c3c129.png)

コンテナアプリケーション作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/51abbf83-d267-9105-3068-fb3b7c6dc32d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/1b56be0d-429f-33eb-6b30-83a0a9a2cd95.png)

### 段階的なコンポーネント作成可能
```helloHeading.cmp
<aura:component>
    <h1>W E L C O M E</h1>
</aura:component>
```

```helloWorld.cmp
<aura:component>
    <c:helloHeading/>
    <p>Hello Lightning!</p>
</aura:component>
```

```harnessApp.app
<aura:application>
    <c:helloWorld/>
</aura:application>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/9e114dc3-79a2-f0ef-3f08-01afab7160ee.png)

### CHALLENGE
```campingList.cmp
<aura:component >
	<ol>
        <li>Bug Spray</li>
        <li>Bear Repellant</li>
        <li>Goat Food</li>
    </ol>
</aura:component>
```
```campingHeader.cmp
<aura:component >
    <h1>Camping List</h1>
</aura:component>
```
```campingHeader.css
.THIS {
}
h1.THIS{
    font-size:18px;
}
```
```camping.cmp
<aura:component >
    <c:campingHeader/>
    <c:campingList/>
</aura:component>
```
## コンポーネントの属性と式
### コンポーネント属性定義（Parameter）
<<aura:attribute>>タグを使用して定義され、name属性とtype属性の値が必要です。省略可能なdefault属性、description属性、required
```<aura:attribute name="message" type="String"/>```
#### 作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/4e488120-5989-f80b-1220-4ca14ccabee3.png)

```helloMessage.cmp
<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>{!$Label.c.Greeting + v.message}</p>
</aura:component>
```
**<<aura:attribute>>
・[name]はパラメータ名です、該当コンポーネントにこのパラメータ利用する時、設定のname値で呼び出し。
・[type]はパラメータの型です、利用できるデータ型は
　①プリミティブデータ型：Boolean、Date、DateTime、Decimal、Double、Integer、Long、String など
　②標準オブジェクト型とカスタムオブジェクト型：Account、MyCustomObject__cなど
　③コレクション型：List、Map、Setなど
　④カスタムApexクラス
　⑤Aura.Component、Aura.Component[]などのフレームワーク固有の型。**

<font color="red">**[$Label]と[v.message]は値プロバイダ、[値プロバイダ]のタグ参照してください。**</font>

#### 呼び出し
```test.app
<aura:application >
	<c:helloMessage message="You look nice today."/>
</aura:application>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/bd068699-8c80-8750-7f8c-e9e772221b8b.png)


#### ※値プロバイダ
オブジェクトがプロパティやメソッドをカプセル化する場合と同じようなやり方で関連する値をまとめてカプセル化します。
###### コンポーネントの値プロバイダ
**・[v.]：**コンポーネント属性セット
**・[c.]：**コンポーネントのコントローラ
###### グローバル値プロバイダ
**[globalID]：**コンポーネントのグローバル ID を返します。すべてのコンポーネントには一意の globalId があります。
**[$Browser]：**アプリケーションにアクセスしているブラウザのハードウェアおよびオペレーティングシステムに関する情報を返します。
**[$ContentAsset]：**Lightning コンポーネントのアセットファイルとして使用される画像、スタイルシート、JavaScript を参照できます。
**[$Label]：**コードの外部に保存されたラベルにアクセスできます。
**[$Locale]：**現在のユーザが選択しているロケールに関する情報を返します。
**[$Resource]：**静的リソースにアップロードした画像、スタイルシート、JavaScript コードを参照できます。

#### データ型サンプル
```expenseItem.cmp
<aura:component>
    <aura:attribute name="expense" type="Expense__c"/>
    <p>Amount:
        <!-- 通貨型表示フォーマット -->
        <lightning:formattedNumber value="{!v.expense.Amount__c}" style="currency"/>
    </p>
    <p>
        Client: {!v.expense.Client__c}
    </p>
    <p>
        <!-- チェックボックス設定 -->
        <lightning:input type="toggle"
                         label="Reimbursed?"
                         name="reimbursed"
                         checked="{!v.expense.Reimbursed__c}" />
     </p>
    <!-- Other markup here -->
</aura:component>
```

#### 属性と式で遊ぶ
```helloPlayground.cmp
<aura:component>
    <aura:attribute name="messages" type="List"
        default="['You look nice today.',
            'Great weather we\'re having.',
            'How are you?']"/>
    <h1>Hello Playground</h1>
    <p>Silly fun with attributes and expressions.</p>
    <h2>List Items</h2>
    <p><c:helloMessage message="{!v.messages[0]}"/></p>
    <p><c:helloMessage message="{!v.messages[1]}"/></p>
    <p><c:helloMessage message="{!v.messages[2]}"/></p>
    <h2>List Iteration</h2>
    <aura:iteration items="{!v.messages}" var="msg">
        <p><c:helloMessage message="{!msg}"/></p>
    </aura:iteration>
    <h2>Conditional Expressions and Global Value Providers</h2>
    <aura:if isTrue="{!$Browser.isIPhone}">
        <p><c:helloMessage message="{!v.messages[0]}"/></p>
    <aura:set attribute="else">
        <p><c:helloMessage message="{!v.messages[1]}"/></p>
        </aura:set>
    </aura:if>
</aura:component>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/ad9fc1f1-a83e-ab54-bb05-ea26ec2ff5e7.png)


### CHALLENGE
```campingListItem.cmp
<aura:component >
    <aura:attribute name="item" type="Camping_Item__c" required="true"/>
    <p>Name:
        <ui:outputText value="{!v.item.Name}"/>
    </p>
    <p>Price:
        <lightning:formattedNumber value="{!v.item.Price__c}" style="currency"/>
    </p>
    <p>Quantity:
        <lightning:formattedNumber value="{!v.item.Quantity__c}"/>
    </p>
    <p>Packed:
        <lightning:input type="toggle" label="Packed" name="togglevalue" checked="{!v.item.Packed__c}"/>
    </p>
</aura:component>
```

## コントローラを使用したアクションの処理
onclick()アクション

```helloMessageInteractive.cmp
<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Message of the day: {!v.message}</p>
    <div>
        <lightning:button label="You look nice today."
            onclick="{!c.handleClick}"/>
        <lightning:button label="Today is going to be a great day!"
            onclick="{!c.handleClick2}"/>
        <lightning:button label="tomorrow is going to be a great day!"
            onclick="{!c.handleClick3}"/>
    </div>
</aura:component>
```
```helloMessageInteractiveController.js
({
    handleClick: function(component, event, helper) {
        let btnClicked = event.getSource();         // アクションボタン取得
        let btnMessage = btnClicked.get("v.label"); // ボタンの属性取得
        component.set("v.message", btnMessage);     // 画面のパラメータ再設定
    },
    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");         // 関数のチェーニング
        console.log("handleClick2: Message: " + newMessage);       // JavaScriptコンソールにログメッセージ表示
        component.set("v.message", newMessage);
    },
    handleClick3: function(component, event, helper) {
        component.set("v.message", event.getSource().get("v.label"));    // 関数のチェーニング
    }
})
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/46516740-b2ce-0c1b-fa2d-a1afb7f78112.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/5aa5f57c-b1ee-3286-afaf-7f387539904f.png)

コントローラ関数を常に宣言してこの 3 つのパラメータを取る必要があります
```handleClick: function(component, event, helper) {```
・component — コンポーネント。この場合は、helloMessageInteractive です。
・event — アクションハンドラをコールする原因となったイベント。
・helper — コンポーネントのヘルパー。再利用可能な関数の別の JavaScript リソースです。

### CHALLENGE
campingListItem.cmpの最後にボタン追加

```campingListItem.cmp
<aura:component >
    ・・・・・
    <!-- ボタン追加、packItem呼び出し -->
    <lightning:button label="Packed！" onclick="{!c.packItem}"/>
</aura:component>
```

```campingListItemController.js
({
    packItem : function(component, event, helper) {
        let a = component.get("v.item",true);
        a.Packed__c = true;
        component.set("v.item",a);
        let btnClicked = event.getSource();
        btnClicked.set("v.disabled",true);
    }
})
```

## フォームを使用したデータの入力
### アプリにSLDSのエクステンド（導入）
Lightningアプリケーションを作成し、SLDS導入声明する（このハーネスアプリケーションは、単なるラッパー、つまりシェルです。）
```<aura:application extends="force:slds">```

SLDSを付けている
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/6408f92a-008c-c825-afa7-2853fabf222c.png">
SLDSを付けない
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/10513442-0185-5b75-14e2-085edb17f50a.png">

```expenses.cmp
<aura:component>
    <aura:attribute name="expenses" type="Expense__c[]"/>
    <aura:attribute name="newExpense" type="Expense__c"
         default="{ 'sobjectType': 'Expense__c',
                        'Name': 'test',
                        'Amount__c': 0,
                        'Client__c': '',
                        'Date__c': '2021-10-21',
                        'Reimbursed__c': true }"/>
    <!-- PAGE HEADER -->
    <lightning:layout class="slds-page-header slds-page-header_object-home">
        <lightning:layoutItem>
            <lightning:icon iconName="standard:scan_card" alternativeText="My Expenses"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="horizontal-small">
            <div class="page-section page-header">
                <h1 class="slds-text-heading_label">Expenses</h1>
                <h2 class="slds-text-heading_medium">My Expenses</h2>
            </div>
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / PAGE HEADER -->
    <!-- NEW EXPENSE FORM -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
            <!-- CREATE NEW EXPENSE -->
            <div aria-labelledby="newexpenseform">
                <!-- BOXED AREA -->
                <fieldset class="slds-box slds-theme_default slds-container_small">
                <legend id="newexpenseform" class="slds-text-heading_small
                  slds-p-vertical_medium">
                  Add Expense
                </legend>
                <!-- CREATE NEW EXPENSE FORM -->
                <form class="slds-form_stacked">
                    <lightning:input aura:id="expenseform" label="Expense Name"
                                     name="expensename"
                                     value="{!v.newExpense.Name}"
                                     required="true"/>
                    <lightning:input type="number" aura:id="expenseform" label="Amount"
                                     name="expenseamount"
                                     min="0.1"
                                     formatter="currency"
                                     step="0.01"
                                     value="{!v.newExpense.Amount__c}"
                                     messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
                    <lightning:input aura:id="expenseform" label="Client"
                                     name="expenseclient"
                                     value="{!v.newExpense.Client__c}"
                                     placeholder="ABC Co."/>
                    <lightning:input type="date" aura:id="expenseform" label="Expense Date"
                                     name="expensedate"
                                     value="{!v.newExpense.Date__c}"/>
                    <lightning:input type="checkbox" aura:id="expenseform" label="Reimbursed?"
                                     name="expreimbursed"
                                     checked="{!v.newExpense.Reimbursed__c}"/>
                    <lightning:button label="Create Expense"
                                      class="slds-m-top_medium"
                                      variant="brand"
                                      onclick="{!c.clickCreate}"/>
                </form>
                <!-- / CREATE NEW EXPENSE FORM -->
              </fieldset>
              <!-- / BOXED AREA -->
            </div>
            <!-- / CREATE NEW EXPENSE -->
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / NEW EXPENSE FORM -->
</aura:component>
```
```expensesControll.js
({
    clickCreate: function(component, event, helper) {
        let validExpense = component.find('expenseform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validExpense){
            // Create the new expense
            let newExpense = component.get("v.newExpense");
            console.log("Create expense: " + JSON.stringify(newExpense));
            helper.createExpense(component, newExpense);
        }
    }
})
```
```expensesHelper.js
({
    createExpense: function(component, expense) {
        let theExpenses = component.get("v.expenses");
        // Copy the expense to a new object
        // THIS IS A DISGUSTING, TEMPORARY HACK
        let newExpense = JSON.parse(JSON.stringify(expense));
        theExpenses.push(newExpense);
        component.set("v.expenses", theExpenses);
    }
})
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/1253511e-e4ac-ac01-a3c4-e679729986b4.png)

### CHALLENGE

```campingHeader.cmp
<aura:component >
    <lightning:layout class="slds-page-header slds-page-header--object-home">
        <lightning:layoutItem>
            <lightning:icon iconName="action:goal" alternativeText="My Camping"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="horizontal-small">
            <div class="page-section page-header">
                <h1 class="slds-text-heading--label">Camping</h1>
                <h2 class="slds-text-heading--medium">Camping List</h2>
            </div>
        </lightning:layoutItem>
    </lightning:layout>
</aura:component>
```

```campingList.cmp
<aura:component >
    <aura:attribute name="items" type="Camping_Item__c[]"/>
        <aura:attribute name="newItem" type="Camping_Item__c" default="{'Name':'',
            'Quantity__c':0,
            'Price__c':0,
            'Packed__c':false,
            'sobjectType':'Camping_Item__c'}"/>
            
            <!-- NEW Campaing FORM -->
            <div class="slds-col slds-col--padded slds-p-top--large">
                
                
                <c:campingHeader/>
                <div aria-labelledby="newCampaingForm">
                    
                    <!-- BOXED AREA -->
                    <fieldset class="slds-box slds-theme--default slds-container--small">

                        <legend id="newCampaingForm" class="slds-text-heading--smallslds-p-vertical--medium">
                            Add Expense
                        </legend>

                        <!-- CREATE NEW Campaing FORM -->
                        <form class="slds-form--stacked">

                        <!-- For Name Field -->
                        <lightning:input aura:id="expenseform" label="Camping Name"
                            name="expensename"
                            value="{!v.newItem.Name}"
                            required="true"/>
                        <!-- For Quantity Field -->
                        <lightning:input type="number" aura:id="campingform" label="Quantity"
                            name="expenseamount"
                            min="1"
                            value="{!v.newItem.Quantity__c}"
                            messageWhenRangeUnderflow="Enter minimum 1 Quantity"/>
                        <!-- For Price Field -->
                        <lightning:input aura:id="campingform" label="Price"
                            formatter="currency"
                            name="expenseclient"
                            value="{!v.newItem.Price__c}"/>
                        <!-- For Check Box -->
                        <lightning:input type="checkbox" aura:id="campingform" label="Packed"
                            name="expreimbursed"
                            checked="{!v.newItem.Packed__c}"/>

                        <lightning:button label="Create Camping"
                            class="slds-m-top--medium"
                            variant="brand"
                            onclick="{!c.clickCreateItem}"/>
                        </form>
                        <!-- / CREATE NEW EXPENSE FORM -->
                    </fieldset>
                    <!-- / BOXED AREA -->
                                        
                </div>
            <!-- / CREATE NEW EXPENSE -->
            </div>
            <!-- ITERATIING ITEM LISTS -->
            <div class="slds-card slds-p-top--medium">
                
                <c:campingHeader/>
                
                <section class="slds-card__body">
                    <div id="list" class="row">
                        <aura:iteration items="{!v.items}" var="item">
                            <c:campingListItem item="{!item}"/>
                        </aura:iteration>
                    </div>
                </section>
            </div>
            <!-- / ITERATIING ITEM LISTS -->
</aura:component>
```

```campingListController.js
({
clickCreateItem : function(component, event, helper) {
    var validCamping = component.find('campingform').reduce(function (validSoFar, inputCmp) {
        // Displays error messages for invalid fields
        inputCmp.showHelpMessageIfInvalid();
        return validSoFar && inputCmp.get('v.validity').valid;
    }, true);
     
    if(validCamping){
        var newCampingItem = component.get("v.newItem");
        //helper.createCamping(component,newCampingItem);
        var campings = component.get("v.items");
        var item = JSON.parse(JSON.stringify(newCampingItem));
         
        campings.push(item);
         
        component.set("v.items",campings);
        component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c','Name': '','Quantity__c': 0,
        'Price__c': 0,'Packed__c': false });
    }
}
})
```

```campingListItem.cmp
<aura:component >
    <aura:attribute name="item" type="Camping_Item__c" required="true"/>
    <lightning:card title="Camping">
        <p class="slds-p-horizontal--small">
            <p>Name:<ui:outputText value="{!v.item.Name}"/></p>
            <p>Price:<lightning:formattedNumber value="{!v.item.Price__c}" style="currency"/></p>
            <p>Quantity:<lightning:formattedNumber value="{!v.item.Quantity__c}"/></p>
            <p>Packed:<lightning:input type="toggle" label="Packed" name="togglevalue" 
                                       checked="{!v.item.Packed__c}"/></p>
        </p>
    </lightning:card>
    <lightning:button label="Packed！" onclick="{!c.packItem}"/>
</aura:component>
```

```campingListItemController.js
({
    packItem : function(component, event, helper) {
        let a = component.get("v.item");
        a.Packed__c = true;
        component.set("v.item",a);
        let btnClicked = event.getSource();
        btnClicked.set("v.disabled",true);
    }
})
```

## サーバ側コントローラを使用した Salesforce への接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424429/0a14dc1a-d26a-2c18-f8d0-d54dea738b5c.png)




[画像リンク](https://www.lightningdesignsystem.com/icons/#standard)


# 参考

https://www.lightningdesignsystem.com/

https://developer.salesforce.com/docs/component-library/overview/components