function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Christian Schwabe (x)Christian Schwabe (x) 

LWC: spinner in lightning-datatable with custom component

Hi folks,

I followed this example to have an toogle-input component in my lightning-datatable: https://devlife.tech/lwc/how-to-create-a-custom-column-in-datatable-lwc/
The lightning-databtable show all validation rules in an org.

After successfully implementation I decided to also show a spinner during toogling and reject the toogling when the http response statuscode was not 204 (success). That is the point it was getting curious.

The validation rule ist active, I toogle it and during the toogling a spinner is shown and the validation rules is getting disabled and the toogle is also unchecked. Everything is fine. I click again on the toogle and the spinner appear again and the toogle is getting active again and the validation also. Everything works fine.
BUT NOW, when I click again on the toogle the spinner is not getting active again during apex callout.

Do you know why the code behave like this way?

Here is the code for investigation and support:

toogleValidationRule.html
<template>
    <!--Custom component which will be rendered as each cell in custom column in datatable-->
    <div>
        <template if:true={isLoading}>
            <lightning-spinner alternative-text="Loading" size="small"></lightning-spinner>
        </template>

        <lightning-input 
            type="toggle" 
            variant="label-hidden" 
            message-toggle-active="On"
            message-toggle-inactive="Off"
            checked={checked}
            onchange={handleToggle}>
        </lightning-input>
    </div>
</template>

toogleValidationRule.js
import { LightningElement, api, track } from 'lwc';

/******************
 * MODULES
 ******************/
import { reduceErrors } from 'c/lwcUtil';
import { notifyUser } from 'c/toastMessageHelper';
import { createNotifyMessage } from 'c/toastMessageHelper';

/******************
 * APEX METHODS
 ******************/
import toogleValidationRule from '@salesforce/apex/DataloadSwitchController.toogleValidationRule';


export default class ToogleValidationRule extends LightningElement {

    /*****************************
     * PUBLIC REACTIVE PROPERTIES
     *****************************/
    @api rowId;// Id of validation rule.
    @api manageableState;// Indicates the manageable state of the specified component that is contained in a package: beta, deleted, deprecated, deprecatedEditable, installed, installedEditable, released, unmanaged
    @api validationName;// Api name of validation rule.
    @api entityDefinitionId;// The entity definition for the object associated with the validation rule.

    /*****************************
     * PUBLIC FUNCTIONS
     *****************************/
     // Indicate if validation rule is active or inactive.
    @api 
    get checked()
    {
        return this._checked;
    }

    set checked(value)
    {
        this._checked = value;
    }

    /*****************************
     * PRIVATE REACTIVE PROPERTIES
     *****************************/
    @track isLoading = false;// Indicate if spinner is enabled (true).
    @track _checked;// Is used in public function checked().

    /*****************************
     * PRIVATE PROPERTIES
     *****************************/
    hasRendered = false;// Indicate if component rendered the first time.

    /******************
     * LIFECYCLE HOOKS
     ******************/
    connectedCallback()
    {
        //console.log('>>>ToogleValidationRule (' + this.validationName + ') -- connectedCallback.');
        this.isLoading = true;
        //console.log('>this.isLoading: ' + JSON.stringify(this.isLoading, null, '\t'));
    }

    renderedCallback()
    {
        //console.log('>this.isLoading: ' + JSON.stringify(this.isLoading, null, '\t'));
        //console.log('>this.hasRendered: ' + JSON.stringify(this.hasRendered, null, '\t'));

        if( ! this.hasRendered)
        {
            console.log('>>>ToogleValidationRule (' + this.validationName + ') -- renderedCallback.');

            this.hasRendered = ! this.hasRendered;
            this.isLoading = false;
            console.log('>this.isLoading: ' + JSON.stringify(this.isLoading, null, '\t'));
        }
    }

    /******************
     * TEMPLATE
     ******************/
    get buttonDisabled()
    {
        return this.manageableState !== 'unmanaged' ? true : false;
    }

    /*handleClick()
    {
        this.checked = ! this.checked;
        this.isLoading = ! this.isLoading;
    }*/

    /******************
     * EVENT HANDLER
     ******************/
    handleToggle(event)
    {
        console.log('>>>BEGIN ToogleValidationRule -- handleToggle.');
        console.log('>event.detail: ' + JSON.stringify(event.detail, null, '\t'));
        const checked = event.detail.checked;
        
        console.log('>#1');
        this.isLoading = true;
        console.log('>this.isLoading: ' + JSON.stringify(this.isLoading, null, '\t'));
        toogleValidationRule({ validationRuleId: this.rowId, state: checked })
            .then(result => {
                console.log('>#2');
                //console.log('>>>ToogleValidationRule -- then().');
                //console.log('>result: ' + JSON.stringify(result, null, '\t'));
                const httpResponse = JSON.parse(result);

                this.handleResponse(httpResponse, checked);
                console.log('>#4');
                //this.isLoading = false;
                console.log('>this.isLoading: ' + JSON.stringify(this.isLoading, null, '\t'));
            })
            .catch(error => {
                console.error('>error: ' + JSON.stringify(error, null, '\t'));
                /*notifyUser(
                    'Error!',
                    reduceErrors(error).join(', '),
                    'error',
                    'sticky'
                );*/
                this.isLoading = false;
                this.checked = ! checked;
            })
        
        console.log('>>>END ToogleValidationRule -- handleToggle.');
    }

    /******************
     * HELPER FUNCTIONS
     ******************/
    handleResponse(httpResponse, checked)
    {
        console.log('>#3');
        console.log('>>>BEGIN ToogleValidationRule -- handleResponse.');

        console.log('>httpResponse: ' + JSON.stringify(httpResponse, null, '\t'));
        console.log('>checked: ' + JSON.stringify(checked, null, '\t'));
        const statusCode = Number(httpResponse.statusCode);
        console.log('>statusCode: ' + JSON.stringify(statusCode, null, '\t'));



        let notifyMessage = {};
        switch (statusCode) {
            case 204:
                console.log('>204');
                this.checked = checked;
                this.isLoading = false;
                console.log('>this.checked: ' + JSON.stringify(this.checked, null, '\t'));
                /*notifyMessage = createNotifyMessage(
                    `${this.validationName} on ${this.entityDefinitionId} was updated.`,
                    null,
                    'success',
                    'pester'
                );*/
                break;
            default:
                const body = JSON.parse(httpResponse.body);
                console.log('>body: ' + JSON.stringify(body, null, '\t'));
                this.checked = ! checked;// Revert change state when it is not allowed.
                this.isLoading = false;
                console.log('>this.checked: ' + JSON.stringify(this.checked, null, '\t'));
                */notifyMessage = createNotifyMessage(
                    'Error!',
                    reduceErrors(body).join(', '),
                    'error',
                    'sticky'
                )*/
                break;
        }
        console.log('>notifyMessage: ' + JSON.stringify(notifyMessage, null, '\t'));

        */notifyUser(
            notifyMessage.title,
            notifyMessage.message,
            notifyMessage.variant,
            notifyMessage.mode
        );*/

        console.log('>>>END ToogleValidationRule -- handleResponse.');
    }
}



Best regards,
Christian
Best Answer chosen by Christian Schwabe (x)
Christian Schwabe (x)Christian Schwabe (x)
Hi guys,

found the issue by myself. The wired apex method was annotated with @AuraEnabled(cacheable=true). I changed it to @AuraEnabled(cacheable=true) because cachine is not needed when you make a callout.

Best regards,
Christian

All Answers

Christian Schwabe (x)Christian Schwabe (x)
Here is an animated gif, which shows the problem in more detail: https://giphy.com/gifs/ohAokNGYur3yv0PjJi

Again:
We are initiating a Tooling API call when switching a Checkbox Toggle and while we wait for the response, we are showing a Spinner to the user. This works as expected – but only two times. If the Toggle is switched a third time, no Spinner is shown. We have checked the console log multiple times but can't detect any difference in the third run.

We've also talked to Alba Rivas, to indentify the problem, but we were not able to solve it.

We have tested different Webbrowsers, for example: I've tested it with different browser (Chrome [Version 86.0.4240.198 (Offizieller Build) (x86_64)] and Safari [Version 14.0.1 (16610.2.11.51.8)]) on my MacBook pro.
We have also disabled 'Enable secure and persistent browser caching to improve performance'.

Does someone has some other ideas?

Best regards,
Christian
Christian Schwabe (x)Christian Schwabe (x)
Hi guys,

found the issue by myself. The wired apex method was annotated with @AuraEnabled(cacheable=true). I changed it to @AuraEnabled(cacheable=true) because cachine is not needed when you make a callout.

Best regards,
Christian
This was selected as the best answer