Salesforce LWC learns the problems and solutions of the recordId of quick action under lwc

Reference to this article:

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 learning (36) Quick Action supports the selection of LWC

When we use lwc, the embedding of recordId and the function of wire adapter greatly reduce our development pressure and make us happy to use it. Later, with the continuous enhancement of release, lwc also supports quick action. We also talked about this in the previous chapter. The use of recordId was not very deep. With the use of a function of quick action, a hidden description (or a bug directly) of recordId under lwc was found. Let's start with a common code that looks ok

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);
    }
}

Configure this lwc as a quick action, select lightning web component as the type, and find an account. Let's see the effect.

The display is normal, no problem. We sometimes use quick action for callout or background interaction. Of course, we can use headless quick action, but for the sake of beautiful UI, we can use screen's quick action to display spinner at run time and disappear at the end of run, so that users will not think the page is fake dead. Let's go to the next code presentation.

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());
        });
    }
}

At first glance, it seems that there is no problem at all. Let's actually run it

An error is reported, indicating that there is no recordId. We copy the code and put it on the lightning record page. It is found that the code runs normally. Only when it is used as a quick action, the recordId is null??? Of course, not only renderedcallback, but also recordId is empty under connectedcallback. We find the document and prompt that recordId can be used normally only when the UI context is displayed. It is not supported in other cases. Of course, the reason for the error is that recordId is not judged to be non empty. This is mainly to expose the problem. If non empty verification is used, the background will not be executed.

So the question is, what is explicit record context? Where can we find out? At least lwc's documents are not viewed, so we need to find Aura's documents first, because aura is the first version of lightning experience. We just need to look at the force:hasRecordId's documents to try our luck. Fortunately, we found the document and learned what is the context of the display record.

 

Through the description, I feel that this is a problem caused by the compatibility of lwc quick action, or a bug, because it does not conform to the description of the context of displaying records, and the same code can take effect when it is placed on the record page as a component. Of course, since the problem is found, you can find the workaround scheme. To solve this problem, three workaround schemes have been proposed, and each scheme can be tested to solve the problem.

1. The front-end display recordId can be placed in the div setting style="display:none", which meets the requirements of the display record context. If the js content is displayed on the front-end, it will be forcibly embedded.

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 first judges that the recordId is not empty

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 type quick action, aura with lwc combination YYDS

testQuickActionForAura. CMP: the recordId embedded under aura is normal

<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'));
        });
    }
}

The js of lwc calls the background. After running, event dispatch and aura close quick action modal. This method is effective for personal testing.

3. Use the CurrentPageReference to obtain the recordId, and then execute the background method

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());
            });
        }

    }
}

Simple demonstration: after clicking the button, you can get the recordId normally and run normally

Summary: only the problem of recordId in lwc quick action is exposed in this article. Other situations are normal temporarily, and three workaround schemes are used. The demo in this article does not consider caching or optimize the code. Interested partners optimize it by themselves. There are better ways to welcome communication. Welcome to point out the mistakes in this article. If you don't understand the welcome message.

Added by eatfishy on Wed, 05 Jan 2022 10:35:45 +0200