5

My use case is to have a button inside a Salesforce Napili Community, which updates the Case.Status field of the record displayed

The logic for the button should be quite simple:

  • IF Case.IsClosed = 'True' - button text to read "Closed" - button disabled
  • IF Case.Status = 'New' or 'Awaiting Customer' - button text to read "Submit" - on click updates Case.Status to 'Submitted'
  • ELSE button text to read "Withdraw Case" - on click updates Case.Status to 'Withdrawn'

I have been struggling with creating this Lightning Component / Apex class with no luck, so thought I'd reach out to see if anyone can help at all? (Please)

Unfortunately I am not a developer so swimming in the deep end. My current code currently doesn't even let me put the button on the Community page as I get the error "Unable to parse JSON response" so it's very wrong.

Component

<aura:component controller="UpdateCaseStatusController_LC" implements="forceCommunity:availableForAllPageTypes" access="global" >
     <aura:handler name="init" value="{!this}" action="{!c.init}"/>
     <aura:attribute name="case" type="Case"/>
     <aura:attribute name="recordId" type="String"/>

<ui:button aura:id="mybtn" class="slds-button slds-button--brand slds-size--1-of-1" label="{!v.case.Status}" press="{!c.onclick}" disabled="{!v.case.IsClosed == true ? 'true' : 'false'}"/>
</aura:component>

Controller:

({    
init : function(component, event, helper) {
    var action = component.get("c.getCase");
    action.setParams({"recordId": component.get("v.recordId")});

    action.setCallback(this, function(response) {
        var state = response.getState();
        if(component.isValid() && state == "SUCCESS"){
            var c = response.getReturnValue();
            component.set("v.case", c);
            window.setTimeout(
                $A.getCallback(function () {
                    var button = component.find("mybtn");
                    if(c.Status == "New" || c.Status == "Awaiting Customer"){
                        button.set("v.label","Submit");
                    }else if(c.Status == "Closed"){
                        button.set("v.label","Closed");
                    }else {
                        button.set("v.label","Withdraw Case");
                    }
                })
            );    

        } else {
            console.log('There was a problem : '+response.getError());
        }
    });
    $A.enqueueAction(action);
},

onclick : function(component, event, helper) {
    var action = component.get("c.saveCase");
        action.setParams({"recordId": component.get("v.recordId")});
    if (callback) {
        action.setCallback(this, callback);
    }
    $A.enqueueAction(action);
}
})

Apex:

public class UpdateCaseStatusController_LC {

@AuraEnabled
public static Case getCase(Id recordId){
    Case caseRec = [SELECT Id, isClosed, Status FROM Case WHERE id=:recordId];
    return caseRec;
}

@AuraEnabled
public static Case saveCase(Id recordId){
    Case caseRec = [SELECT Id, Status FROM Case WHERE id=:recordId];

    if (caseRec.Status == 'New' || caseRec.Status == 'Awaiting Customer') {
        caseRec.Status = 'Submitted';
    } else {
        caseRec.Status = 'Withdrawn';
    }

    update caseRec;
    return caseRec;
}}
1
  • You are passing 2 params in method saveCase. It takes only one of type Case.
    – S..
    Mar 13 '17 at 6:13
3

A couple of things, Your getCase method returns an object of type "case", But, you are setting the object to a String in the init method of your js Controller.Additionally, as N.B pointed out, you seem to be passing 2 arguments when your apex method saveCase is expecting only one argument of type case.

Below is a refined version of your logic for your use-case. I have hard-coded "recordId" for demo purposes, do modify as required. And I notice that you have used individual aura:attributes for properties such as Status and Closed. Instead we ought to use compound attributes such as Object or Array of Objects for better logic.

Component:

<aura:component controller="SampleCaseController" implements="forceCommunity:availableForAllPageTypes" access="global" >
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
    <aura:attribute name="case" type="Case"/>

    <ui:button aura:id="mybtn" class="slds-button slds-button--brand" label="{!v.case.Status}" press="{!c.onclick}" disabled="{!v.case.IsClosed == true ? 'true' : 'false'}"/>

</aura:component>

We could have used aura:if for conditional rendering of status just like how we have used for "disabled" attribute. However extensive usage of aura:if is not recommended. Hence we will do our conditional checks in JS Controllers.

Apex Controller :

public class SampleCaseController {
    @AuraEnabled
    public static Case getCase(Id recordId){
        Case mycase = [SELECT Id, isClosed, Status FROM Case WHERE id=:recordId];
        return mycase;
    }
}

Controller.js :

({
    init : function(component, event, helper) {
        var recordId = "50061000007fHbf"; // for demo purpose

        var action = component.get("c.getCase");
        action.setParams({"recordId": recordId});

        action.setCallback(this, function(response) {
            var state = response.getState();
            if(component.isValid() && state == "SUCCESS"){
                var c = response.getReturnValue();
                component.set("v.case", c);
                window.setTimeout(
                    $A.getCallback(function () {
                        var button = component.find("mybtn");
                        if(c.Status == "New" || c.Status == "Awaiting Customer"){
                            button.set("v.label","Submit");
                        }else if(c.Status == "Closed"){
                            button.set("v.label","Closed");
                        }else {
                            button.set("v.label","Withdraw Case");
                        }

                    })
                );

            } else {
                console.log('There was a problem : '+response.getError());
            }
        });
        $A.enqueueAction(action);

    },
    onclick : function(component, event, helper) {
        console.log("Your save logic goes here");
    }

})

We will require window.setTimeout to provide small delay during the aura render cycle. If not the updated values will not reflect in the DOM.

Results :

New Status

When Status is new, the button text is set to "Submit"

New Community

Working Status

Status anything other than New or Awaiting Customer, the text is set to "Withdraw Case"

Withdrawn Community

Status Changed to Closed

Closed Status

Button Disabled in the Community and Status changed to closed

Closed Community

Update :

Change the methods below as shown and your save method should work during onclick.

Apex Controller :

@AuraEnabled
public static Case saveCase(Case caseRec){

        if (caseRec.Status == 'New' || caseRec.Status == 'Awaiting Customer') {
            caseRec.Status = 'Submitted';
        } else {
            caseRec.Status = 'Withdrawn';
        }

        update caseRec;
        return caseRec;
    }

I have changed the parameter from RecordId to caseRec as to avoid an additional database query.

Controller.js :

onclick : function(component, event, helper) {

        var action = component.get("c.saveCase");
        action.setParams({"caseRec": component.get("v.case")});

        action.setCallback(this, function(response) {
            var state = response.getState();
            if(component.isValid() && state == "SUCCESS"){
                var c = response.getReturnValue();
                component.set("v.case", c);
            } else {
                console.log('There was a problem : '+response.getError());
            }
        });
        $A.enqueueAction(action);

}

The other components do not require any change. The status would display as expected.

Results :

When status is set to working

Working Status

The status is set to Withdraw case in community :

Withdrawn Community

When you click on withdraw case, the button text and case status change to "Withdrawn"

Withdrawn Case Status Withdrawn

6
  • Thanks Sumuga, that's gold. However, I am still struggling with getting the button to save the record with an updated status, & also for the button to use the status of the case displayed. I've updated my code above. Can you help again please?
    – Howard
    Mar 14 '17 at 4:07
  • @Howard : I have updated the answer. Change the couple of methods shown above and rest should work fine. Mar 14 '17 at 5:53
  • @Howard : Hope it resolved your queries. Mar 14 '17 at 15:21
  • Thank you loads Sumuga, this worked perfectly, and I now understand what I had wrong so you have improved my knowledge as well. Thanks
    – Howard
    Mar 15 '17 at 13:13
  • Note that the variable name in action.setParams() must match the variable name in the declaration of the Apex method - in this case "caseRec". That tripped me up. Sep 5 '19 at 18:24
0

i have a similar requirement. I am using a lightning component behind a button on quote object(custom object). when user click on this button if quote status is approved show user a alert that quote is already approved if its not approve then change quote status to approve. Below is my code i am getting attempt to de reference null object.

component:

controller: public class ApproveQuoteController { @AuraEnabled public static FConnect__Service_Quote__c getQuote(Id quoteId) { return [select id,name,FConnect__Account__c,FConnect__Status__c,FConnect__Contact__c,FConnect__Site__c,FConnect__Problem__c from FConnect__Service_Quote__c where id=:quoteId]; }

@AuraEnabled
public static FConnect__Service_Quote__c saveQuote(FConnect__Service_Quote__c quote){

    quote.FConnect__Status__c = 'Approved';

    update quote;
    return quote;
}

} JS: ({ doInit : function(component, event, helper) {

        var action = component.get("c.saveQuote");
        var action2 = component.get("c.getServerSideMessage");
        action.setParams({"quote": component.get("v.quote")});

        action.setCallback(this, function(response) {
            var state = response.getState();
            if(component.isValid() && state == "SUCCESS"){
                var c = response.getReturnValue();
                component.set("v.quote", c);
            }
            else if (state === "ERROR"){
                var errors = action2.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        cmp.set(“v.message”, errors[0].message);
                    }
                }
            }    
            else {
                console.log('There was a problem : '+response.getError());
            }
        });
        $A.enqueueAction(action);

} 

})

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.