1. 程式人生 > >salesforce lightning零基礎學習(六)Lightning Data Service(LDS)

salesforce lightning零基礎學習(六)Lightning Data Service(LDS)

tin 變化 mod mes find chage dem 哪些 eat

本篇可參看:https://trailhead.salesforce.com/modules/lightning_data_service

Lightning中針對object的detail頁面,一個lightning app可能包含了多個components,多個components不可避免的會對這個數據進行CRUD操作,如果我們針對每個component都在init操作時後臺SQL進行查詢,然後賦值給前臺變量,進行CUD操作時,還要考慮其他component的數據是否要級聯的改變,這種操作以及設計對於性能的影響還是蠻大的,有什麽好的方法可以做到一次搜索或者一次加載,所有的components都共用嗎?這個時候,LDS或許可以是你想要的。

lightning中,我們使用 Lightning Data Service(LDS)去服務於數據層面,LDS 提供了對數據的訪問。

LDS除了可以讓一個app的所有的component共用一個share的數據,這樣一個更新以後,所有的component(model 為view)都會同步的刷新這個數據。還可以支持用戶離線操作數據,當網絡連接以後,用戶對數據的操作則會進行同步。

LDS優點概括來說:

最小化的XMLHttpRequests

數據只需要搜索一次。

跨 components 分享數據記錄

當數據改變以後會創建通知。

優點還有很多,當一個app 涉及到記錄的簡單的增刪改查操作,使用LDS是一個最優的方式。

說了這麽多LDS的優點,那LDS如何使用呢?其實只需要在component中引入 <force:recordData>標簽即可。

一. <force:recordData>屬性介紹
<force:recordData>標簽包含以下的常用屬性:

recordId : 指定哪條記錄來加載,此字段為必須字段。

mode: 指定當前的模式,有 View和Edit兩個值。如果針對當前component有update操作,則mode設置為Edit。此字段為必須字段

layoutType: 決定了哪個layout用於加載, FULL/COMPACT。

fields: 決定哪些字段用來搜索出來

layoutType以及fields至少有一個要求必須,因為管理員擁有更改pagelayout的權限,所以layoutType加載的字段具有不確定性,推薦使用fields。

targetRecord: 此屬性相當於這條記錄ID對應的記錄變量,通過此變量可以訪問fields中指定的字段值。

targetFields: targetRecord對應的字段的視圖,通過此字段可以取出fields中的指定的值。

通過上面的描述可以看出來targetRecord以及targetFields均可以取出fields中指定的字段值,他們兩個寫法盡管不同,但是他們的表達含義以及取得值相同,後面有具體的描述。

targetError: 此屬性存儲Error Message, 如果記錄沒有正確的提供。

recordUpdated:此屬性指定當記錄進行了CUD操作時的事件處理。

簡單Demo如下:其中 {v.accountFields.Name} 等同於{!v.record.fields.Name}.

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
    <aura:attribute name="record" type="Object"/>
    <aura:attribute name="accountException" type="String"/>
    <aura:attribute name="accountFields" type="Object"/>
    <force:recordData
        recordId="{!v.recordId}"
        aura:id="accId"
        targetRecord="{!v.record}"
        targetFields="{!v.accountFields}"
                targetError="{!v.accountException}"
        fields="Id,Name,Industry"
        mode="VIEW"/>
    <lightning:card title="{!v.accountFields.Name}">
        <lightning:formattedText title="Industry" value="{!v.record.fields.Industry}"/>
    </lightning:card>
</aura:component>

二. LDS的 CUD,錯誤提示以及自帶的事件監聽操作

force:recordData組件元素自帶了好幾個方法用來實現數據的簡單的增刪改操作。controller.js中通過獲取到force:recordData元素後調用相關的方法即可進行DML操作。常用方法如下:

  • getNewRecord():創建一條新記錄,通常用於insert操作,init handler中調用此方法創建一條ID為空的記錄,此方法不會返回任何類型的callback function;
  • saveRecord(): 用於 insert/update記錄,此方法會返回一個 SaveRecordResult對象的callback function,SaveResult後面會詳細介紹;
  • deleteRecord():用於記錄的delete操作,此方法會返回一個SaveRecordResult對象的callback function。

通過上面的常用的三個方法,我們會關註到SaveRecordResult這個對象,此類作為CUD操作的callback返回的唯一參數,此對象具有以下的字段:

  • objectApiName:當前操作的object的 API name;
  • entityLabel: 當前操作的object的label name;
  • error: 如果發生系統或者自定義的操作此記錄的錯誤,則返回在error字段裏面,此error字段返回的類型為list,可以通過for循環叠代出所有的錯誤信息。如果當前的操作狀態為操作成功(save state為success或者draft)則error為undefined;
  • recordId: 當前操作記錄的18位的ID;
  • state: 返回當前操作的結果狀態: SUCCESS(操作成功)/ DRAFT(Server不可達,本地存儲成功)/ INCOMPLETE(Server不可達,本地不支持存儲)/ERROR(存儲錯誤,由於validation或者其他的原因)。

getNewRecord():此方法用於創建一個空的記錄,方法有四個參數:

  • objectApiName: 需要創建的 object 的API name;
  • recordTypeId: 需要創建的object的record type 的ID,如果沒有指定,默認為default record type;
  • skipCache:判斷是否從server端獲取object的template還是從客戶端獲取;
  • callback:當object創建完以後的回調函數,此函數沒有任何參數,創建完成以後會自動調用此方法。

saveRecord():此方法用於create/edit操作,方法只有一個參數:

  • callback:當object create/update完成以後的回調函數,次函數也包含了一個參數,即上面提到的SaveResultResult對象的變量引用。

deleteRecord():此方法用於delete操作,方法也只有一個參數:

  • callback:當object delete完成以後的回調函數,次函數也包含了一個參數,即上面提到的SaveResultResult對象的變量引用。

上面說過,通過LDS可以在數據變化後,共用的component實時的刷新數據,但是當兩個同樣的字段同時在Edit 模式下,則不會同時刷新,即刷新數據僅限於View模式下。

舉個例子:Account 新增一個 Action,用來展示和更新Account的部分字段信息。

1). accDisplay.cmp : 用來展示主要的幾個字段

 1 <aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
 2     <aura:attribute name="record" type="Object"/>
 3     <aura:attribute name="accountException" type="String"/>
 4     <aura:attribute name="recordFields" type="Object"/>
 5     <force:recordData
 6         recordId="{!v.recordId}"
 7         aura:id="accId"
 8         targetRecord="{!v.record}"
 9         targetFields="{!v.recordFields}"
10         fields="Name,AccountNumber,Site"
11         mode="VIEW"
12         />
13     <lightning:card title="Acc View" iconName="action:info">
14         <lightning:formattedText title="Name" value="{!v.recordFields.Name}"/>
15         <br/>
16         <lightning:formattedText title="Account Number" value="{!v.recordFields.AccountNumber}"/>
17         <br/>
18         <lightning:formattedText title="Site" value="{!v.recordFields.Site}"/>
19         <br/>
20 
21     </lightning:card>
22 </aura:component>

2). accEdit2.cmp:更新固定的幾個字段

 1 <aura:component implements="force:hasRecordId, 
 2                             force:lightningQuickActionWithoutHeader">
 3     <aura:attribute name="record" 
 4                     type="Object" description="current record reference"/>
 5     <aura:attribute name="recordFields" 
 6                     type="Object" description="current record fields list"/>
 7     <aura:attribute name="recordError"
 8                     type="String" description="if error occurs,record error reference"/>
 9     
10     <force:recordData aura:id="editRecordId"
11                       fields="Name,AccountNumber,Site"
12                       recordId="{!v.recordId}"
13                       targetError="{!v.recordError}"
14                       targetRecord="{!v.record}"
15                       targetFields="{!v.recordFields}"
16                       mode="EDIT"
17                       />
18     
19     <!-- Display an editing form -->
20     <div class="Edit Account Details">
21         <lightning:card iconName="action:edit" title="{!v.recordFields.Name}">
22             <div class="slds-p-horizontal--small">
23 
24                 <lightning:input label="Name" 
25                                  value="{!v.recordFields.Name}"/>
26                 <br/>
27                 <lightning:input label="Account Number" 
28                                  value="{!v.recordFields.AccountNumber}"/>
29                 <br/>
30                 <lightning:input label="Site" 
31                                  value="{!v.recordFields.Site}"/>
32                 <br/>
33 
34                 <lightning:button label="Save" 
35                                   variant="brand" 
36                                   onclick="{!c.handleSaveRecord}"/>
37             </div>
38         </lightning:card>
39     </div>
40     
41     <!-- if error occurs, display operate error -->
42     <aura:if isTrue="{!not(empty(v.recordError))}">
43         <div class="recordError">
44             {!v.recordError}
45         </div>
46     </aura:if>
47 </aura:component>

3). AccComponent.cmp: 通過Tab方式展示數據信息,因為想要測試一個場景,所以此component裏面引用了兩遍accEdit2.cmp

 1 <aura:component implements="flexipage:availableForAllPageTypes,force:lightningQuickAction,force:hasRecordId">
 2     <lightning:tabSet class="slds-tabs_scoped">
 3         <lightning:tab label="Acc View">
 4             <c:AccDisplay recordId="{!v.recordId}"/>
 5         </lightning:tab>
 6         <lightning:tab label="Acc Edit">
 7             <c:AccEdit2 recordId="{!v.recordId}"/>
 8         </lightning:tab>
 9         <lightning:tab label="Acc Edit2">
10             <c:AccEdit2 recordId="{!v.recordId}"/>
11         </lightning:tab>
12     </lightning:tabSet>
13 </aura:component>

4). 新建一個Lightning Action,並且將此Action放在Page Layout中

技術分享圖片

結果展示:

1.點擊Edit Test會彈出Pop Up Window

技術分享圖片

2.在ACC EDIT Tab輸入了內容點擊Save以後,結果展示位ACC View的Tab會立刻顯示輸入後save的內容,而ACC Edit2 Tab則會保留原值。

技術分享圖片

通過結果可以看出來,在mode為view情況下,save以後會立刻顯示在view視圖中。在mode為Edit情況下,如果edit1有某個字段更新,比如Account Number,則edit2的Account Number不會被更新。這種設計也是正常的,因為如果同步更新會有歧義,但是我們有一些場景還是希望Edit模式下也可以自動更新這些值得,這個時候就可以使用到自帶的事件監聽。

自帶事件監聽使用非常簡單,只需要<force:recordData>標簽增加屬性:recordUpdated屬性設置你需要後臺controller綁定的handler即可。

使用LDS的事件監聽有4中類型: CHANGED / LOADED / REMOVED / ERROR。 從名字可以看出來分別對應著 更改 / 加載 / 移除 / 錯誤。

下面我們針對上面的程序進行改進,對accEdit2.cmp 優化一下force:recordData組件元素

1 <force:recordData aura:id="editRecord2Id"
2                       fields="Name,AccountNumber,Site"
3                       recordId="{!v.recordId}"
4                       targetError="{!v.recordError}"
5                       targetRecord="{!v.record}"
6                       targetFields="{!v.recordFields}"
7                       mode="EDIT"
8                       recordUpdated="{!c.reloadUpdate}"
9                       />

對accEdit2Controller.js增加一個reloadUpdate方法,其中調用reloadRecord()方法可以對force:recordData進行重新數據加載。

 1 reloadUpdate : function(component, event, helper) {
 2         var eventParams = event.getParams();
 3         if(eventParams.changeType == "CHANGED") {
 4             // get the changed fields for this record
 5             var changedFields = eventParams.changedFields;
 6             console.log(‘Chaged Fields: ‘ + JSON.stringify(changedFields));
 7             component.find(‘editRecordId‘).reloadRecord();
 8         } else if(eventParams.changeType === "LOADED") {
 9             console.log("Record is loaded successfully.");
10         } else if(eventParams.changeType === "REMOVED") {
11             var deleteRecordResult = $A.get("e.force:showToast");
12             deleteRecordResult.setParams({
13                 "title": "Delete Result",
14                 "message": "The record was deleted."
15             });
16             deleteRecordResult.fire();
17         } else if(eventParams.changeType === "ERROR") {
18             console.log(‘Error: ‘ + component.get("v.error"));
19         }
20 }

增強上述方法以後,在重新運行,當ACC Edit Tab中改了相關的值以後,ACC Edit2 Tab的值也會同步的更新,因為LDS已經加載成了最新的值。

(註意:調用reloadRecord()方法以後,會重新執行事件類型為LOADED的事件設置,demo中如果save以後會打出Record is loaded successfully.)

總結:使用LDS可以在不使用controller情況下便進行簡單的CUD操作,很類似classic 中的standcontroller功能。這種方式在lightning中還是很常見的,但是如果涉及到復雜的數據關聯的改動或者transaction中需要進行多次更新操作,建議不使用LDS換成後臺controller中去做。篇中只弄了Edit的demo,new以及delete的demo感興趣的可以自己去玩。篇中有錯誤的歡迎指出,有問題歡迎留言。

salesforce lightning零基礎學習(六)Lightning Data Service(LDS)