1

I have a lightning component which includes a spinner rendered by this code:

<aura:component access="global" 
    controller="SomeAuraController"
    implements="flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickActionWithoutHeader"
>
    <ltng:require scripts="{!$Resource.AURA_LightningPromiseHelper_JS}" />

    <div aura:id="spinner" class="slds-spinner_container slds-hide">
       <div class="slds-spinner--brand  slds-spinner slds-spinner--large slds-is-relative" role="alert">
         <span class="slds-assistive-text">Updating</span>
         <div class="slds-spinner__dot-a"></div>
         <div class="slds-spinner__dot-b"></div>
       </div>
    </div>

    <lightning:recordEditForm objectApiName="Contact" recordId="{!v.recordId}" 
          onsubmit="{!c.update}"
    >
      <lightning:inputField fieldName="LastName" />
        <lightning:button type="submit"/>
    </lightning:recordEditForm>
</aura:component>

My component requires a static resource which successfully controls the spinner with the following:

// See: http://bobbuzzard.blogspot.hu/2016/12/javascript-promises-in-lightning_30.html
const $LPH = (function(){
    const alterSpinner = function(methodName) {
        return (component) => {
            $A.util[methodName](component.find('spinner'), 'slds-hide');
        };
    };

    const showSpinner = alterSpinner('removeClass');
    const hideSpinner = alterSpinner('addClass');

    const ServerApexPromise = (component, serverMethodName, serverMethodParams) => {
        const action = component.get('c.' + serverMethodName);
        action.setParams(serverMethodParams);

        return new Promise((resolve, reject) => {
            showSpinner(component);
            action.setCallback(this, (response) => {
                hideSpinner(component);
                if (response.getState() === 'SUCCESS') {
                    resolve(response.getReturnValue())
                }
                else {
                    const errors = response.getError();
                    const errorMessage = (errors && errors[0] && errors[0].message)
                        ? 'Error message: ' + errors[0].message
                        : 'Unknown error';
                    reject (errorMessage);
                }
            });
            $A.enqueueAction(action);
        });
    };

    return {
        ServerApexPromise: ServerApexPromise
    };
}());

window.$LPH = $LPH;

In between, the controller has code like this:

sendCancel: function  (component, event, helper) {
    event.preventDefault();

    $LPH.ServerApexPromise(
       component, 
       'update', 
       {contact: event.getParam('fields')}
    )
        .then(helper.onSuccess(), helper.onFailure());
}

In order to make my outer component more concise and facilitate reuse, I'd like to move this code into a separate component (e.g. "LightningSpinner"):

<aura:component>
<div aura:id="spinner" class="slds-spinner_container  slds-hide">
   <div class="slds-spinner--brand  slds-spinner slds-spinner--large slds-is-relative" role="alert">
     <span class="slds-assistive-text">Loading</span>
     <div class="slds-spinner__dot-a"></div>
     <div class="slds-spinner__dot-b"></div>
   </div>
</div>
</aura:component>

However, when I replace the original component code with <c:LightningSpinner />, the spinner stops working.

What am I overlooking? How can I fix this?

1

By looking at your code I think all you need to do is replace your spinner markup with

<lightning:spinner aura:id="spinner" />

What I can think of by looking at your code is that you have created a static resource to call server side actions. Whenever a action is called you are toggling spinner.

In Lightning:spinner's documentation it is given that we just need to toggle slds-hide to show or hide spinner. So your existing logic of showing and hiding spinner will work.

If you don't want to use salesforce standard component and use your own component then

<aura:component>
<aura:attribute name="class" type="string" default="slds-hide"/>
<div aura:id="spinner" class="{! "slds-spinner_container" + v.class}">
   <div class="slds-spinner--brand  slds-spinner slds-spinner--large slds-is-relative" role="alert">
     <span class="slds-assistive-text">Loading</span>
     <div class="slds-spinner__dot-a"></div>
     <div class="slds-spinner__dot-b"></div>
   </div>
</div>
</aura:component>

Then in your method

 const alterSpinner = function(className) {
            return (component) => {
                component.find('spinner').set("v.class", className);
            };
        };
const showSpinner = alterSpinner('slds-show');
    const hideSpinner = alterSpinner('slds-hide');

Lets say your component name is c:lightSpinner

replace your spinner markup in main component with

<c:lightSpinner aura:id="spinner"/>
-1

you can use standard Salesforce Lightning:Spiner Component From Salesforce.PFB the link. https://developer.salesforce.com/docs/component-library/bundle/lightning:spinner/example

PFB the sample Code:

<!--Sample.cmp-->
<aura:component controller="SampleAuraController" implements="flexipage:availableForAllPageTypes,force:appHostable">
    <!--Component Start-->
    <div class="slds-m-around_xx-large">
        <lightning:button label="Click Me" variant="brand" onclick="{!c.handleClick}"/>
        <lightning:spinner aura:id="mySpinner" alternativeText="Processing.." title="Processing.." variant="brand" size="large" class="slds-hide"/>
    </div>
    <!--Component End-->
</aura:component>

Lightning Component JS Controller:

({
    handleClick: function (component, event, helper) {
        helper.showSpinner(component);
        var action = component.get('c.getMessage');
        action.setCallback(this,function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                helper.hideSpinner(component);
            }
        });
        $A.enqueueAction(action);
    }
})

Lightning Component JS Helper:

({
    showSpinner: function (component, event, helper) {
        var spinner = component.find("mySpinner");
        $A.util.removeClass(spinner, "slds-hide");
    },

    hideSpinner: function (component, event, helper) {
        var spinner = component.find("mySpinner");
        $A.util.addClass(spinner, "slds-hide");
    }
})

Call showspiner and hidespiner From Js Controller on buttonclick.

-1

Here is a way to do it using aura:method and no addClass/removeClass. First, create a MySpinner component like so:

MySpinner.cmp

<aura:component>

    <aura:attribute name="Spinner" type="Boolean"/>

    <aura:method name="show" action="{!c.show}"/>
    <aura:method name="hide" action="{!c.hide}"/>

    <aura:if isTrue="{!v.Spinner}">
        <lightning:spinner aura:id="MySpinner" variant="brand" size="large" alternativeText="Loading..."/>
    </aura:if>  

</aura:component>

MySpinner ControllerJS

({
    show: function(component, event, helper){
        component.set("v.Spinner", true);
    },

    hide: function(component, event, helper){
        component.set("v.Spinner", false);
    }
})

Then in the component where you would like to show the spinner (say, someRandomComponent.cmp), declare an instance of MySpinner.cmp in the markup like so:

<c:MySpinner aura:id="MySpinner"/>

someRandomComponent.cmp HelperJS

showHideSpinner: function(component, event, helper, show){
    try{
        var spinnerAuraId = 'MySpinner';
        var spinner = component.find(spinnerAuraId); //look for MySpinner element at this level
        if(!spinner)
            spinner = component.getSuper().find(spinnerAuraId); //if not found at this level, look for MySpinner element at parent level (in case this component extends another component that contains MySpinner declaration)

        if(show)
            spinner.show();
        else
            spinner.hide();
    } catch(err){
        console.log('-------> showHideSpinner ERROR: ' + err + ' ** MESSAGE: ' + err.message + ' ** STACK: ' + err.stack);
    }
},

Finally, this is how you can invoke the spinner from any JS method in someRandomComponent.cmp

someRandomComponent.cmp ControllerJS or HelperJS

doSomething: function(component, event, helper) {
    //show spinner by setting the 'show' param to true
    helper.showHideSpinner(component, event, helper, true);
    //-- do something -- 
    //when done, hide the spinner
    helper.showHideSpinner(component, event, helper, false);
}
  • Beyond "spinner", I'm not clear how this relates to the question. That's not the sort of change I was trying to make. – Brian Kessler Sep 12 '18 at 10:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.