本篇參考:
https://developer.salesforce.com/docs/component-library/bundle/force:hasRecordId/documentation
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/use_record_context
Salesforce LWC學習(三十六) Quick Action 支援選擇 LWC了
我們在使用lwc的時候,recordId的嵌入以及wire adapter的功能,極大的減輕了我們的開發壓力,讓我們很爽的使用著。後來隨著release的不斷增強,lwc也支援quick action。這個我們在之前的篇章也講過。曾經對recordId的使用不是很深入,隨著quick action的一個功能的使用,發現了recordId在lwc下的一個隱藏描述(或者直接說是bug也好)。我們先來一個大家常用並且看上去沒有問題的程式碼
testLwcQuickAction.html
<template> <lightning-quick-action-panel header="Test LWC Quick Action"> {name} </lightning-quick-action-panel> </template>
testLwcQuickAction.js
import { LightningElement, track, wire,api } from 'lwc'; import { CloseActionScreenEvent } from 'lightning/actions'; import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; import NAME_FIELD from '@salesforce/schema/Account.Name'; export default class testLwcQuickAction extends LightningElement { @api recordId; @wire(getRecord, { recordId: '$recordId', fields: [NAME_FIELD]}) account; get name() { return getFieldValue(this.account.data, NAME_FIELD); } }
將這個lwc配置成一個quick action,型別選擇lightning web component,找到一條account,我們看一下效果。
展示正常,沒啥問題。那我們有時候會使用quick action做callout或者後臺互動,當然可以使用headless的quick action,但是為了UI美觀,我們可以使用screen的quick action,執行時展示 spinner,執行結束消失,讓使用者不會以為頁面假死。我們進行下個程式碼展示。
TestLwcQuickActionController.cls
public with sharing class TestLwcQuickActionController { @AuraEnabled(cacheable=false) public static Boolean updateAccount(String accountId) { Account accountItem = new Account(); accountItem.Id = accountId; accountItem.Name = 'updated account : ' + String.valueOf(System.now()); update accountItem; return true; } }
testLwcQuickAction2.html
<template> <lightning-quick-action-panel header="Test LWC Quick Action"> </lightning-quick-action-panel> </template>
testLwcQuickAction2.js
import { LightningElement, track, wire,api } from 'lwc'; import { CloseActionScreenEvent } from 'lightning/actions'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import updateAccount from '@salesforce/apex/TestLwcQuickActionController.updateAccount'; export default class testLwcQuickAction2 extends LightningElement { @api recordId; renderedCallback() { updateAccount({accountId : this.recordId}) .then(result => { console.log(result); let event = new ShowToastEvent({ title: 'update success', variant: 'success' }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }) .catch(error => { console.log(JSON.stringify(error)); let event = new ShowToastEvent({ title: 'error occurs', variant: "error" }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }); } }
乍一眼看上去是不是一點問題都沒有,讓我們實際執行一下
竟然報錯了,提示沒有recordId,我們將這個不作為 lwc 的quick action,複製這個程式碼,放在 lightning record page發現程式碼正常執行,只有作為quick action情況下,recordId為null??? 當然,不止renderedCallback, connectedCallback下,recordId同樣為空。我們找到文件,提示只有顯示UI的上下文才可以正常的使用 recordId,其他的情況下則不支援。當然,報錯原因是 recordId我們沒有判斷非空,這個主要是為了暴露問題,如果使用非空驗證,仍然不會執行後臺。
那麼問題來了,什麼是 explicit record context?我們哪裡可以查到呢? 至少lwc的文件中沒有檢視到,所以我們需要先找到 aura的文件,因為aura是lightning experience的第一版,我們只需要看一下 force:hasRecordId的文件去碰一下運氣看看有沒有即可。很幸運地是,我們找到了文件,並且瞭解了什麼算是顯示記錄的上下文。
通過描述愈發的感覺這是因為 lwc quick action的相容性導致的問題,或者說是一個bug,因為這個並不符合說的顯示記錄的上下文的描述,而且同樣程式碼作為元件放在record page即可以生效。當然問題既然發現,找到workaround方案就可以了。解決這個問題,目前想到3種 workaround方案,每個方案都親測可以解決問題。
1. 前端展示 recordId,放在 div 設定 style="display:none"即可,這樣就滿足了顯示記錄上下文的要求,將js內容前端展示,則會強制嵌入。
testLwcQuickAction2.html
<template> <lightning-quick-action-panel header="Test LWC Quick Action"> <div style="display: none;"> {recordId} </div> </lightning-quick-action-panel> </template>
testLwcQuickAction2.js:renderedCallback先判斷recordId非空
import { LightningElement, track, wire,api } from 'lwc'; import { CloseActionScreenEvent } from 'lightning/actions'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import updateAccount from '@salesforce/apex/TestLwcQuickActionController.updateAccount'; export default class testLwcQuickAction2 extends LightningElement { @api recordId; renderedCallback() { if(this.recordId) { updateAccount({accountId : this.recordId}) .then(result => { console.log(result); let event = new ShowToastEvent({ title: 'update success', variant: 'success' }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }) .catch(error => { console.log(JSON.stringify(error)); let event = new ShowToastEvent({ title: 'error occurs', variant: "error" }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }); } } }
2. aura型別quick action,aura搭配lwc的組合YYDS
testQuickActionForAura.cmp: aura下嵌入 recordId正常
<aura:component implements="force:hasRecordId,force:lightningQuickActionWithoutHeader"> <aura:attribute name="recordId" type="String"></aura:attribute> <c:testSonLwcQuickAction recordId="{!v.recordId}" onclosemodal="{!c.handleCloseAction}"></c:testSonLwcQuickAction> </aura:component>
testQuickActionForAuraController.js
({ handleCloseAction : function(component, event, helper) { $A.get('e.force:refreshView').fire(); $A.get("e.force:closeQuickAction").fire(); } })
testSonLwcQuickAction.js
import { LightningElement, track, wire,api } from 'lwc'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import updateAccount from '@salesforce/apex/TestLwcQuickActionController.updateAccount'; export default class testSonLwcQuickAction extends LightningElement { @api recordId; renderedCallback() { updateAccount({accountId : this.recordId}) .then(result => { console.log(result); let event = new ShowToastEvent({ title: 'update success', variant: 'success' }); this.dispatchEvent(event); this.dispatchEvent(new CustomEvent('closemodal')); }) .catch(error => { console.log(JSON.stringify(error)); let event = new ShowToastEvent({ title: 'error occurs', variant: "error" }); this.dispatchEvent(event); this.dispatchEvent(new CustomEvent('closemodal')); }); } }
lwc的js呼叫後臺,執行以後,event dispatch,aura關閉quick action modal,此種方式親測有效。
3. 使用CurrentPageReference獲取recordId,獲取以後,再去執行後臺方法
testLwcQuickAction.html
<template> <lightning-quick-action-panel header="Test LWC Quick Action"> </lightning-quick-action-panel> </template>
testLwcQuickAction.js
import { LightningElement, track, wire,api } from 'lwc'; import { CloseActionScreenEvent } from 'lightning/actions'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; import { CurrentPageReference } from 'lightning/navigation'; import updateAccount from '@salesforce/apex/TestLwcQuickActionController.updateAccount'; export default class testLwcQuickAction3 extends LightningElement { @track recordId; @wire(CurrentPageReference) pageRef; renderedCallback() { if(this.pageRef && this.pageRef.state) { this.recordId = this.pageRef.state.recordId; updateAccount({accountId : this.recordId}) .then(result => { console.log('*** result : ' + result); let event = new ShowToastEvent({ title: 'update success', variant: 'success' }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }) .catch(error => { console.log(JSON.stringify(error)); let event = new ShowToastEvent({ title: 'error occurs', variant: "error" }); this.dispatchEvent(event); this.dispatchEvent(new CloseActionScreenEvent()); }); } } }
簡單演示:點選按鈕以後,可以正常的獲取 recordId並且可以正常的執行
總結: 篇中只是暴露出recordId在lwc quick action下的問題,其他的情況暫時使用正常,以及3種workaround方案。篇中demo中沒有考慮快取,也沒有優化程式碼,感興趣的小夥伴自行優化。有更好的方法歡迎交流溝通。篇中錯誤地方歡迎指出,有不懂歡迎留言。