本篇參考:
GitHub - trailheadapps/dreamhouse-lwc: Sample application for Lightning Web Components on Salesforce Platform. Part of the sample gallery. Real estate use case. Get inspired and learn best practices.
Salesforce LWC學習(三十) lwc superbadge項目實現
背景描述: 我們今天看的demo是salesforce的dream house的UI,這個demo在 salesforce developer gallary中可以查詢到,上述的git hub是它的源代碼。主要功能是一個賣房的應用,可以通過條件查詢需要的房源,點擊房源可以查看到房源詳情以及中介詳情等信息,和我們之前做的superbadge整體功能很相似,使用到的技術以及排版等基本相同,即一個 lightning app builder中有幾個 lwc component,通過message channel進行組件間通訊。大概UI如下圖所示
本來這個是一個沒啥好說的demo,但是眼神好的我看到了右側的詳情頁面是可以編輯的。因爲詳情頁的組件使用的 lightning-record-form,只要有權限,就會展示編輯頁面。問題就來了。
1. 如果右側的信息更改了,中間的內容是否可以動態改變呢?
2. 如果中間內容不能級聯改變的話,需要什麼樣的交互方式可以通知他進行動態改變呢?
針對以上的兩個問題,第一個是當前的代碼肯定沒法動態改變,所以我們需要改變我們的代碼。第二個問題,我們可以使用message channel,但除了 message channel以外,我們還有沒有其他的方式進行跨組件交互呢? 這裏引出了我們今天的主角: Dynamic Interaction.
一. Dynamic Interaction
我們應該在今年年初的新聞中,就可能看到過salesforce針對 lightning app builder要推出一個low code工具用來實現不同組件之間的交互。使用Dynamic Interaction,Lightning頁面上某個組件中發生的事件,例如用戶單擊列表視圖中的某個item,可以更新頁面上的其他組件。Dynamic Interactions允許管理員使用基於用戶交互的組件創建應用程序,所有這些組件都在Lightning App Builder UI中進行通信和轉換。官方的demo中,舉得是列表點擊,詳情頁展示的demo,類似於了 message channel的功能。那Dynamic Interaction 有什麼需要考慮的?
- 當目標組件的屬性顯示在事件屬性編輯器中時,將忽略目標組件中的信息組件。
- 如果爲包含動態交互的頁面切換頁面模板,則可用模板列表僅顯示支持動態交互的模板。
- 當觸發以Aura Component爲目標的交互時,Aura Component會重新渲染。
- 在富文本編輯器中輸入表達式時,autocomplete不起作用。
- 組件的事件元數據在Lightning頁面上使用或作爲託管包的一部分發布後,不允許進行某些破壞性更改,例如刪除事件、重命名屬性或更改屬性類型。
有什麼限制呢?
- Dynamic interaction 目前只支持在 app page
- 只有LWC自定義組件可以是事件源,但頁面上出現的任何組件(Aura或LWC)都可以是目標組件。
- 基於自定義頁面模板的頁面不支持Dynamic Interaction(目前只能使用官方的那幾個標準的 app template)。
- 只有String和Rich Text類型的屬性可以使用表達式來定義它們的值。
- Event是交互中表達式支持的唯一上下文。
- 只能對String、Integer和Boolean類型的屬性使用表達式。
- 不能將目標屬性值設置爲數組或列表,例如多選選擇列表。
- 可以使用metadata API將String屬性的目標屬性值設置爲空,但不能在Lightning App Builder UI中設置。
- Dynamic Interaction在Salesforce移動應用程序或傳統平板電腦移動體驗中的Mobile Only應用程序中不起作用。
- 當依賴屬性根據所做的選擇或在另一個屬性中輸入的值自動填充時,除非通過單擊或tab 去 focus在依賴屬性字段,否則不會保存自動填充的值。
所以使用之前需要注意瞭解這些限制,否則配置完成以後很容易產生困惑爲什麼不生效。
二. Dynamic Interaction的使用方法
我們以下面的demo進行講解,下圖是 Dream House的組件組成部分。我們所需要用到以及改動的是propertyTileList以及 proprtySummary
我們先修改一下 propertySummary的代碼。
propertySummary.html: lightning-record-form 增加了 onsuccess邏輯
<lightning-record-form object-api-name="Property__c" record-id={propertyId} fields={propertyFields} columns="2" onsuccess={handleSuccessAction} > </lightning-record-form>
propertySummary.js: 增加這個方法,創建一個自定義的事件。
handleSuccessAction(event) { let updatePropertyId = JSON.stringify(new Date()); const itemUpdated = new CustomEvent('itemUpdated', { detail: {updateTimeStamp: updatePropertyId} }); this.dispatchEvent(itemUpdated); }
propertySummary.js-meta.xml:在 targetConfig 爲 lightning_AppPage下,增加以下粗體的 event屬性以及schema屬性。其中 property內容設置我們要傳遞的參數
<?xml version="1.0" encoding="UTF-8" ?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>55.0</apiVersion> <isExposed>true</isExposed> <masterLabel>Property Summary</masterLabel> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> </targets> <targetConfigs> <targetConfig targets="lightning__AppPage"> <supportedFormFactors> <supportedFormFactor type="Large" /> <supportedFormFactor type="Small" /> </supportedFormFactors> <event name="itemUpdated" label="Item Updated" description="This event fires when an item is Updated."> <schema> { "type": "object", "properties": { "updateTimeStamp": { "type": "string", "title": "Update timestamp", "description": "changed time stamp value" } } } </schema> </event> </targetConfig> <targetConfig targets="lightning__RecordPage"> <objects> <object>Property__c</object> </objects> <supportedFormFactors> <supportedFormFactor type="Large" /> <supportedFormFactor type="Small" /> </supportedFormFactors> </targetConfig> </targetConfigs> </LightningComponentBundle>
propertyTileList.js:
import { LightningElement, wire,track,api } from 'lwc'; import { publish, subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; import FILTERSCHANGEMC from '@salesforce/messageChannel/FiltersChange__c'; import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; import getPagedPropertyList from '@salesforce/apex/PropertyController.getPagedPropertyList'; import { refreshApex } from '@salesforce/apex'; const PAGE_SIZE = 9; export default class PropertyTileList extends LightningElement { pageNumber = 1; pageSize = PAGE_SIZE; searchKey = ''; maxPrice = 9999999; minBedrooms = 0; minBathrooms = 0; @track clickedPropertyId; @track previousTimeStamp; @api set updateTimeStamp(value) { if(this.previousTimeStamp != value) { refreshApex(this.properties); this.previousTimeStamp = value; } } get updateTimeStamp() { return this.previousTimeStamp; } @wire(MessageContext) messageContext; properties; @wire(getPagedPropertyList, { searchKey: '$searchKey', maxPrice: '$maxPrice', minBedrooms: '$minBedrooms', minBathrooms: '$minBathrooms', pageSize: '$pageSize', pageNumber: '$pageNumber' }) wiredProperties(result) { this.properties = result; } connectedCallback() { this.subscription = subscribe( this.messageContext, FILTERSCHANGEMC, (message) => { this.handleFilterChange(message); } ); } disconnectedCallback() { unsubscribe(this.subscription); this.subscription = null; } handleFilterChange(filters) { this.searchKey = filters.searchKey; this.maxPrice = filters.maxPrice; this.minBedrooms = filters.minBedrooms; this.minBathrooms = filters.minBathrooms; } handlePreviousPage() { this.pageNumber = this.pageNumber - 1; } handleNextPage() { this.pageNumber = this.pageNumber + 1; } handlePropertySelected(event) { const message = { propertyId: event.detail }; this.clickedPropertyId = message; this.updateTimeStamp = message; publish(this.messageContext, PROPERTYSELECTEDMC, message); } }
propertyTileList.js-meta.xml
<?xml version="1.0" encoding="UTF-8" ?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>55.0</apiVersion> <isExposed>true</isExposed> <masterLabel>Property Tile List</masterLabel> <targets> <target>lightning__AppPage</target> </targets> <targetConfigs> <targetConfig targets="lightning__AppPage"> <property name="updateTimeStamp" type="String"></property> <supportedFormFactors> <supportedFormFactor type="Large" /> <supportedFormFactor type="Small" /> </supportedFormFactors> </targetConfig> </targetConfigs> </LightningComponentBundle>
以上是代碼改動部分。接下來是配置部分。因爲這個是自定義的 template的 lightning app page,所以並不支持 dynamic interaction。
我們使用標準的 template,然後將這兩個組件拖動出來。這裏選中了 propertyTileSummary組件以後,右側就可以顯示 Interaction 這個 Tab,我們就可以點擊 Add Interaction去設置 dynamic interaction.
這裏source以及event是沒法更改的,目前 interaction只支持Update Properties,後續有可能會新增。updateTimeStamp使用 {!event.}的方式進行動態的賦值。實現propertySummary的事件註冊以後,就會將變量動態交互賦值給 propertyTileList的updateTimeStamp變量。我們將這個字段設置了set,只要有變量,就refreshApex,從而實現只要右側組件更新,左側的列表也會自動的更新。
至此配置完成。結果展示如下:
1. 我們點擊了一個item,右側進行編輯,將3更改成2.
2. save以後,左側的列表也會自動的變更。
總結: dynamic interaction目前支持性還是有限,但是salesforce按照目前的情況後續還會不斷的增強。瞭解目前的限制以及如何實現就OK,期待後續可以更多的使用場景以及更少的限制。篇中有錯誤歡迎指出,有不懂歡迎留言。