[SalesForce] Lightning button to update a record

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

Best Answer

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

Related Topic