Trailhead学习:Lightning Components Basics

【Trailhead学习】开发者2考试解锁之路:”Lightning组件框架专家”(Lightning Component Framework Specialist Superbadge)之Lightning Components Basics 。

该模块为 Aura模块基础(Aura Components Basics)
https://trailhead.salesforce.com/en/content/learn/modules/lex_dev_lc_basics

分为如下几个单元:

  • Before You Start
  • Get Started with Lightning Components
  • Create and Edit Lightning Components
  • Attributes and Expressions
  • Handle Actions with Controllers
  • Input Data Using Forms
  • Connect to Salesforce with Server-Side Controllers
  • Connect Components with Events
  • Discover Next Steps

该模块是解锁Lightning Component Framework Specialist Superbadge的第二个Module。其中Lightning Component Framework Specialist Superbadge的链接如下:

https://trailhead.salesforce.com/en/content/learn/superbadges/superbadge_lcf

本模块的主要学习目的是:利用Lightning Components中的可重用的组件构建网页版apps。

在开始前(Before You Start)

相关学习链接如下:
https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_prereqs
学习开发Lightning components 需要学习JavaScript,对于初学者,可以参考如下链接:
JS: The Right Way: http://jstherightway.org/

题目

  • Setting Up Your Org
    As part of our challenges for this module, you’ll build a camping list application. You need to do a few more tasks before passing this challenge and continuing.

  • Create an Expense custom object to work with the examples. You probably already have done this.

    • Create a Camping Item custom object to hold the items you need to go camping with the following fields:
    • Name (use the standard name field)
    • Quantity: Number(18, 0) - Required
    • Price: Currency(16, 2) - Required
    • Packed: Checkbox(default: unchecked)

解析

题目要求新建一个对象(Object)名字为:Expense,相关信息需要设置如下:

  • Label:Expense
  • Plural Label:Expenses
  • Starts with vowel sound:checked
  • API Name:Expense__c

同时新建四个字段在Expense对象上:

  • Amount (API Name:Amount__c),字段类型:Number(16,2)
  • Client (API Name:Client__c),字段类型:Text(50)
  • Date (API Name:Date__c),字段类型:Date
  • Reimbursed (API Name:Reimbursed__c),字段类型:Checkbox

之后需要新建另外一个对象名字为Camping Item,这里API名字可以为Camping_Item__c。同时,新建三个field:Quantity,Price,Packed。

搞定!

image

Get Started with Lightning Components

相关链接:https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_intro

如下是Lightning Components框架,其设计师为了连接Salesforce与lightning平台。

image

题目一:Which of the following descriptions about the Lightning Component framework is true?
A) It’s a UI framework for developing web apps for mobile and desktop devices.
B) It uses JavaScript on the client side and Apex on the server side.
C) It’s a modern framework for building single-page applications.
D) All of the above

解析: Lightning Component适用于移动端和PC端,同时前端是JS,后端是APEX。所以答案是D

题目二:What can you build with the Lightning Component framework?
A) Standalone app
B) Components to use inside Visualforce pages
C) Drag-and-drop components for Lightning App Builder
D) All of the above

解析:本题考查Lightning Component适合应用的场景。D。

题目三:How is Lightning Components different from other web app frameworks?

A) Lightning Components is optimized for both mobile and desktop experiences and proves it with Salesforce1 and Lightning Experience.
B) Lightning Components connects natively with services provided by the Salesforce platform.
C) Lightning Components has specific opinions about how data access is performed and has specific security requirements.
D) All of the above

解析:Lightning Components 和其他框架的不同点。Lightning Components 其设计主要是为了Salesforce服务,也即连接Lightning平台和Salesforce。所以答案是D

Create and Edit Aura Components

相关链接:
https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_create

题目:

Create a Simple Camping List Lightning Component

  • Create a ‘camping’ component that displays a list of camping supplies that you’ll need for your trip. Compose this component by using other components to increase reusability.
  • Create a campingList component that contains an ordered list of camping supplies that include Bug Spray, Bear Repellant, and Goat Food.
  • Create a campingHeader component that displays Camping List wrapped in an H1 tag with a font size of 18.

要新建三个Lightning Component,分别为’camping’,’campingList’,’campingHeader’

其中’campingList’,需要列出三个列表Bug Spray, Bear Repellant, 和 Goat Food。

1
2
3
4
5
6
7
<aura:component >
<ol>
<li>Bug Spray</li>
<li>Bear Repellant</li>
<li>Goat Food</li>
</ol>
</aura:component>

同时新建一个’campingHeader’

1
2
3
<aura:component >
<h1>Camping List</h1>
</aura:component>
1
2
3
4
5
.THIS {
}
h1.THIS {
font-size: 18px;
}

‘camping’代码如下:

1
2
3
4
<aura:component >
<c:campingHeader/>
<c:campingList/>
</aura:component>

image

Attributes and Expressions

相关链接:
https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_attributes_expressions
本章主要讲述的是相关属性以及表达式。
接下来是下一个题目:
Create a Packing List Item Component
Create a Lightning Component to display a single item for your packing list.

  • Create a component called campingListItem.
  • Add an attribute named item of type Camping_Item__c that is required.
  • Display Name, Price, Quantity, Packed using an expression.
  • Display Price and Quantity using the appropriate formatted number fields.
  • Display Packed status using a toggle.

题目要求添加一个Camping_Item__c类型,同时定义Price和Quantity为数字字段。这里我们把Price定义为currency字段:

1
2
3
4
5
6
7
<aura:component >
<aura:attribute name="item" type="Camping_Item__c" required="true"/>
<ui:outputText value="{!v.item.Name}"/>
<lightning:formattedNumber value="{!v.item.Price__c}" style="currency"/>
<lightning:formattedNumber value="{!v.item.Quantity__c}" style="Number"/>
<lightning:input type="toggle" label="Packed" name="togglevalue" checked="{!v.item.Packed__c}" />
</aura:component>

image

Handle Actions with Controllers

相关链接为:https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_controllers

此文主要学习如何使用Controllers

例子

下面我们来根据例子实际学习一下如何使用控制器,这里新建一个Lightning Component 命名为helloMessageInteractive:

1
2
3
4
5
6
7
8
9
10
<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.handleClick}"/>
</div>
</aura:component>

其中’c’是控制客户端的操作。通过onclick调用客户端handleClick的函数实行控制。

接下来是controller来控制按钮:

1
2
3
4
5
6
7
({
handleClick: function(component, event, helper) {
var btnClicked = event.getSource(); // the button
var btnMessage = btnClicked.get("v.label"); // the button's label
component.set("v.message", btnMessage); // update our message
}
})

‘event.getSource()’指向的是用户所点击的按钮属性。之后通过component.set设置客户端的变量”v.message”。

最后还需要新建一个Lightning Application去预览这个组件:

1
2
3
<aura:application extends="force:slds" >
<c:helloMessageInteractive></c:helloMessageInteractive>
</aura:application>

题目

接下来直接进入题目环节:

Mark Item as Packed
Add a button to the campingListItem component that when clicked, marks the item as packed.

  • Add a button labeled Packed! that calls the packItem controller function when clicked.
  • The controller function should do the following:
    • Mark the item attribute as packed using a value of true
    • Disable the button by marking the disabled attribute using a value of true

题目要求新建一个按钮,当按钮按下之后,设置Packed为真。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" >
<!-- item attribute is an instance of Camping_Item__c-->
<aura:attribute name="item" type="Camping_Item__c" description="instance of Camping_Item__c object" required="true" default="{Packed__c : false}" access="global"/>
<p>
Name: {!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>
<lightning:input type="toggle" label="Packed ?" name="Packed" checked="{!v.item.Packed__c}" />
</p>
<lightning:button label="Packed!" onclick="{!c.packItem}"/>
</aura:component>

同时记得Disable这个按钮。

1
2
3
4
5
6
7
8
({
packItem : function(component, event, helper) {
//set the Packed__c property of the item (instance of Camping_Item__c) attribute
component.set("v.item.Packed__c",true);
//set the disabled attribute to true
event.getSource().set("v.disabled",true);
}
})

最后在Lightning Application去预览这个组件:

1
2
3
<aura:application extends="force:slds">
<c:campingListItem item="{Price__c: 100, Packed__c: false, Quantity__c: 10, Name:'Test'}" />
</aura:application>

最后效果图如下:

image

image

搞定!

image

最后,关于Lightning组件的其他库函数可以参考如下官方链接:
Components - Salesforce Lightning Component Library: https://developer.salesforce.com/docs/component-library/overview/components

Input Data Using Forms

链接如下:

https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_forms

本节讲述的是如何利用Lightning组建构建表单,同时表单的样式使用Salesforce Lightning Design System,简称SLDS。

这里,我们再application里面加入 extends=”force:slds”的属性,就可以使用简称SLDS的库。

我们可以现建立一个如下的 lightning component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<aura:component>
<!-- 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>

这里的lightning component用到了lightning:layout,同时设置了size=”6” ,那么对应道HTML里面的div会占用页面宽度的 50%,总数为12。
lightning:input是输入框里面的相关属性和HTML类似,如min是最小值。这里出现一个aura:id是在每一个tag里面的唯一的id
同时,新建一个application:

1
2
3
4
5
<aura:application extends="force:slds">

<!-- This component is the real "app" -->
<c:expenses/>
</aura:application>

效果图如下:
alt tag

下面进入题目环节:

Create a Form to Enter New Items

In this challenge you’ll create a form to enter new items, a list to display the items entered, and add SLDS styling. First, to make our camping list look more appealing, change the campingHeader component to use lightning:layout and SLDS. Similar to the unit, style the Camping List H1 inside the slds-page-header. Add the action:goal SLDS icon using lightning:icon.

Next, modify the campingList component to contain a new item input form and an iteration of campingListItem components for displaying the items entered. Here are additional details for the modifications to the campingList component.

  • Add an attribute named items with the type of an array of camping item custom objects.
  • Add an attribute named newItem of type Camping_Item__c with default quantity and price values of 0.
  • The component displays the Name, Quantity, Price, and Packed form fields with the appropriate input component types and values from the newItem attribute. The Quantity field accepts a number that’s at least 1.
  • Submitting the form executes the action clickCreateItem in the JavaScript controller.
  • If the form is valid, the JavaScript controller pushes the newItem onto the array of existing items, triggers the notification that the items value provider has changed, and resets the newItem value provider with a blank sObjectType of Camping_Item__c. For this challenge, place the code in your component’s controller, not the helper.

题目需要开发者写一个输入的表单,同时展示所有输入的记录。这里我们可以使用SLDS样式,如lightning:icon。

现在开始先写campingList 组件,也是主体部分。需要设置Camping_Item__c的quantity和price的默认值都为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<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--small
slds-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>

接下来需要写一个clickCreateItem函数处理当提交上来的数据,将数据传入newItem中。同时将原来的Camping_Item__c里面的值清空。这里只需要写controller就够了,helper文件就不需要了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
({
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 });
}
}
})

接下来需要写campingHeader函数,展示camping的头信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
<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">My Camping</h2>
</div>
</lightning:layoutItem>
</lightning:layout>
</aura:component>

最后的campingListItem 组件可以沿用上一章节‘Handle Actions with Controllers’里面的代码。

最后新建一个Camping.app,

1
2
3
<aura:application extends="force:slds" >
<c:campingList />
</aura:application>

打开Camping.app,效果如下:

image

就这样,又拿了500分!

image

Connect to Salesforce with Server-Side Controllers

相关链接如下:
https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_server

使用服务器端控制器连接到Salesforce

我们可以参考如下图,在前端,通过View展示给用户,并且通过JS的Controller实现与Salesforce的服务器端控制器进行连接。

image

在上一章节中,我们提及了利用Lightning组建构建表单,相关架构图如下,

image

整个组建由Create按钮开始,该按钮连接到clickCreate动作处理程序。当操作处理程序运行时,它从表单字段(2)中获取值,然后将新expense添加到expense数组(3)。

当通过set更新array时,它会触发组建自动重新列出expense清单(4)。

从Salesforce查询数据

接着上面的框架图,如何实现在应用启动时加载现有数据列表(如expense)?可以参考如下代码:

1
2
3
4
5
6
7
8
9
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];
}
}

一种更为常见的调用方法可以如下。直接通过soql传入查询语句如select id from Account实现动态查询。

1
2
3
4
5
6
@AuraEnabled
public static List<sObject> QueryRecord(String soql){
List<sObject> sobjs = new List<sObject>();
sobjs= Database.query(soql);
return sobjs;
}

“Aura”是Lightning Components核心的开源框架的名称。同时,该 static的关键词。所有@AuraEnabled 控制器方法必须是static方法,并且要么适用 public 要么 global范围。值得注意的另一件事是,该方法对Lightning组件的数据打包没有任何特殊作用,它只是直接返回SOQL查询结果。

从Salesforce加载数据

那么我们怎么通过Aura Components 加载相关的数据呢?
首先,我们需要在aura:component中写入相关的class,如下:

1
<aura:component controller="ExpensesController">

其实,指向Apex控制器实际上并不加载任何数据,也不会调用远程方法。根据上面图示,我们还需要在js调用相关的controller方法(method)。

首先,我们需要在View层定义一开始js跑的函数。如下图所示,我们调用了js端的doInit函数。

1
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>

调用服务器端控制器方法

接下来我看看如何通过js调用服务器端控制器,可以通过component.get(“c.getExpenses”)定义所需要调用的方法。其中,C代表着客户端控制器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Load expenses from Salesforce
doInit: function(component, event, helper) {
// Create the action
var action = component.get("c.getExpenses");
// Add callback behavior for when response is received
action.setCallback(this, function(response) {
var 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);
}

值得注意的是,如果是component.get(“v.something”),代表着在js在前端View层拿数据。action.setCallback(…)的代码块,它将在远程方法调用返回数据时运行。最后,通过$A.enqueueAction(action);实现完整的调用。
通过确定state为SUCCESS之后,将返回的结果由response.getReturnValue()取出。之后赋值给v.expenses。

学了了Aura基本框架之后,我们来看看如下挑战:

  • 使用服务器端控制器保存和加载记录
  • 使用服务器端控制器将记录保留到数据库。该campingList部件载荷现有的记录,当它启动和提交表单时保存记录到数据库中。
  • 使用getItems方法和saveItem方法创建一个CampingListController Apex类。
  • 添加一个doInit初始化处理程序,在组件启动时从数据库加载现有记录。
  • 修改JavaScript控制器以使用帮助程序中的createItem方法从有效的表单提交中将记录保存到数据库。新项目将添加到控制器的项目值提供程序中。

首先根据需要,先需要创建一个CampingListController.cls ,同时需要写两个方法:getItems方法和saveItem方法。
可以参考如下代码:

或者如下链接:
https://gitlab.com/snippets/1807867

getItems方法是获取数据,saveItem方法是保存数据。

campingList.cmp

可以参考如下代码:

或者如下链接:
https://gitlab.com/snippets/1807867

CampingListController.js
然后在前端加载一个doInit初始化处理程序:
可以参考如下代码:

或者如下链接:
https://gitlab.com/snippets/1807868
在组件启动时从数据库调用getItems获得现有记录

同时需要写保存数据的方法,可以参考CampingListHelper.js
可以参考如下代码:

或者如下链接:
https://gitlab.com/snippets/1807869

image

Connect Components with Events

相关链接如下:https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_events

接下来我们学习如何在component中使用event。下面这个例子展示了如何通过component发送event:

1
2
3
4
5
6
7
8
<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”,也就是开关类型。
当用户点击了这个开关,会触发clickReimbursed事件,下面是clickReimbursed事件,会新建一个event名字为updateExpense。同时传入expense 参数。

1
2
3
4
5
6
7
8
({
clickReimbursed: function(component, event, helper) {
var expense = component.get("v.expense");
var updateEvent = component.getEvent("updateExpense");
updateEvent.setParams({ "expense": expense });
updateEvent.fire();
}
})

接下来定义一个event,其中event有两种类型,组件和应用程序类型。这里我们使用的是组件事件,名字为expensesItemUpdate。

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

那么如何发送一个event呢?这里我们需要注册一个event,加上如下代码在expenseItem 组件中。如下代码的意思是埋在本组件里面会触发一个event,名字是updateExpense,其类型为c:expensesItemUpdate。

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

发送了event之后,该如何在主component里面处理呢?

如下代码展示了在主组件expenses中,添加一个aura:handler,接收来自expensesItemUpdate的event,同时会触发一个新的函数handleUpdateExpense。

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

接下来我们看看handleUpdateExpense如何拿到相关event传过来的参数,直接使用event.getParam(“expense”)获取参数,传给helper函数进行相关处理。

1
2
3
4
handleUpdateExpense: function(component, event, helper) {
var updatedExp = event.getParam("expense");
helper.updateExpense(component, updatedExp);
}

最后,updateExpense 的方法可以如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
updateExpense: function(component, expense) {
var action = component.get("c.saveExpense");
action.setParams({
"expense": expense
});
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
// do nothing!
}
});
$A.enqueueAction(action);
}

学习了event如何操作之后,我们来查看相关挑战:

image

Refactor Components and Communicate with Events

Refactor the input form for camping list items into its own component and communicate with component events.

  • Replace the HTML form in the campingList component with a new campingListForm component that calls the clickCreateItem JavaScript controller action when clicked.
  • The campingList component listens for a c:addItemEvent event and executes the action handleAddItem in the JavaScript controller. The handleAdditem method saves the record to the database and adds the record to the items value provider.
  • The addItemEvent event is of type component and has a Camping_Item__c type attribute named item.
  • The campingListForm registers an addItem event of type c:addItemEvent.
  • The campingListFormController JavaScript controller calls the helper’s createItem method if the form is valid.
  • The campingListFormHelper JavaScript helper creates an addItem event with the item to be added and then fires the event. It then resets the newItem value provider with a blank sObjectType of type Camping_Item__c.
  • 使用新的campingListForm组件替换campingList组件中的HTML表单,该组件在单击时调用clickCreateItem JavaScript控制器操作。
  • campingList组件侦听c:addItemEvent事件并在JavaScript控制器中执行操作handleAddItem。该handleAdditem方法保存记录到数据库中并添加记录到的物品价值提供商。
  • 该addItemEvent事件类型的成分和有一个名为Camping_Item__c类型属性的项目。
  • campingListForm注册了一个类型为c的addItem事件:addItemEvent。
  • 如果表单有效,campingListFormController JavaScript控制器将调用帮助程序的createItem方法。
  • campingListFormHelper JavaScript帮助程序使用要添加的项创建addItem事件,然后触发事件。然后,它使用类型为Camping_Item__c的空白sObjectType 重置newItem值提供程序。

相关代码如下:

addItemEvent.evt

1
2
3
<aura:event type="APPLICATION" description="Event template" >
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>

在主组件里面campingList.cmp,这里需要引用<c:campingListForm />,同时添加aura:handler接收来自campingListForm的event,同时触发handleAddItem函数处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<aura:component controller="CampingListController"
implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" access="global" >
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<aura:handler name="addItem" event="c:addItemEvent"
action="{!c.handleAddItem }"/>
<aura:attribute name="items" type="Camping_Item__c[]"/>
<ol>
<li>Bug Spray</li>
<li>Bear Repellant</li>
<li>Goat Food</li>
</ol>
<!-- PAGE HEADER -->

<c:campingHeader />
<lightning:layout >
<lightning:layoutItem padding="around-small" size="6">
<c:campingListForm />
</lightning:layoutItem>
</lightning:layout>
<c:campingHeader />

<div class="slds-card slds-p-top--medium">
<header class="slds-card__header">
<h3 class="slds-text-heading--small">Items</h3>
</header>

<section class="slds-card__body">
<div id="list" class="row">
<aura:iteration items="{!v.items}" var="items">
<c:campingListItem item="{!item}"/>
</aura:iteration>
</div>
</section>
</div>

</aura:component>

这里附上campingListController.js代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
({
// Load expenses from Salesforce
doInit: function(component, event, helper) {

// Create the action
var action = component.get("c.getItems");

// Add callback behavior for when response is received
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
component.set("v.items", response.getReturnValue());
}
else {
console.log("Failed with state: " + state);
}
});

// Send action off to be executed
$A.enqueueAction(action);
},

handleAddItem: function(component, event, helper) {
var newItem = event.getParam("item");
var action = component.get("c.saveItem");
action.setParams({"item": newItem});
action.setCallback(this, function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
var items = component.get("v.items");
items.push(item);
component.set("v.items",items);
}
});
$A.enqueueAction(action);

}
})

在campingListForm.cmp中,我们注册一个Event,名字为addItem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" >
<aura:attribute name="newItem" type="Camping_Item__c" default="{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false }"/>
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<lightning:layout >
<lightning:layoutItem padding="around-small" size="6">
<div aria-labelledby="newcampaignform">
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newcampaignform" class="slds-text-heading--small slds-p-vertical--medium">
Add Campaign List
</legend>
<form class="slds-form--stacked">
<lightning:input aura:id="campaignform" label="Campaign Item Name"
name="campaignitemname"
value="{!v.newItem.Name}"
required="true"/>
<lightning:input type="number" aura:id="expenseform" label="Quantity"
name="campaignitemprice"
min="1"
formatter="number"
step="0.1"
value="{!v.newItem.Quantity__c}"
messageWhenRangeUnderflow="Enter quantity that's at least 1."/>
<lightning:input type="number" aura:id="expenseform" label="Price"
name="campaignitemprice"
min="0.1"
formatter="currency"
step="0.01"
value="{!v.newItem.Price__c}"
messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
<lightning:input type="checkbox" aura:id="expenseform" 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>
</fieldset>
</div>

</lightning:layoutItem>
</lightning:layout>
</aura:component>

当按钮lightning:button按下时候,触发clickCreateItem函数,在campingListFormController.js里面,同时会调用helper.createItem。

1
2
3
4
5
6
7
8
9
10
11
12
13
({
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 addItm = event.getParam("v.newItem");
helper.createItem(component, addItm);
}
}
})

当campingListFormHelper.js中,触发event时候,会调用名字为addItem的注册event。

1
2
3
4
5
6
7
8
9
10
11
12
({
addItem : function(component, campaign) {
var createEvent = component.getEvent("addItem");
createEvent.setParams({ "item": campaign });
createEvent.fire();
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
}
})

Discover Next Steps

相关链接如下:https://trailhead.salesforce.com/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_next_steps

相关题目:

  1. What does SLDS stand for?

A) Salesforce Leadership Does Surf

B) System Limits Detection System

C) Salesforce Lightning Design System

D) sObject Loading Data System

答案:去官网看看https://www.lightningdesignsystem.com/,所以答案是B

  1. What are Lightning Events used for?

A) Salesforce mini developer conferences

B) Communicating between loosely coupled components

C) Logging critical details during app runtime

D) Scheduling sales calls in Lightning Experience

答案:Lightning Events主要用于连接component。所以答案是B

相关参考文献: Events | Lightning Aura Components Developer Guide | Salesforce Developers: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/intro_events.htm

  1. What is the name of the open-source framework that Lightning Components is based on?

A) Aura
B) Angular
C) jQuery
D) WebObjects

答案:本文所有内容都是围绕Aura而展开的。所以答案是A。

  1. In which language do you write Lightning Components action handlers?

A) Java
B) Visualforce
C) JavaScript
D) Objective-C

答案:Lightning Components action 主要是用JavaScript写的,所以答案是C。

就这样我们成功拿下Lightning Components Basics整个模块:

image

image

参考文献: