1

I am trying to add a button to a portal page in Salesforce. Everything on the portal is straight out of the box containing information for a specific users case. I just want to add a button on the page to allow the user to close the case and updates the case status to closed. I can't do this out of the box since I am using a chatter feed and all the buttons go inside and I need it outside. I was able get this done using a visualforce page and I have included the code below, however I am trying to figure out how I can do the same thing using lightning web components.

public without sharing class CloseCaseController
{
    final ApexPages.StandardController controller;
    Public Case myRecord{get;set;}
    
   public CloseCaseController(ApexPages.StandardController controller)
    {
        this.controller = controller;
    }

    public PageReference closeMyCase()
    {
        
        myRecord = (Case)controller.getRecord();
        myRecord.Status = 'Closed';
        
        try
        {
            update record;
        }
        catch (DmlException dmx)
        {
            ApexPages.addMessages(dmx);
            return null;
        }
        return controller.view();
    }

}
<apex:page standardController="Case" extensions="CloseCaseController" docType="html-5.0" applyHtmlTag="false" applyBodyTag="false"
           showHeader="false" sidebar="false" standardStylesheets="false" lightningStylesheets="true"
           title="Close Case">
    <head>
        <apex:slds />
    </head>
    
    <body class="slds-scope" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <apex:form >
            <apex:commandButton value="Close Case" action="{!closeMyCase}" />
        </apex:form>
    </body>
</apex:page>

I have started the LWC as follows. My understanding is I need to remove the CloseCaseController. Do I need to run update SOQL in this class instead? I have also read about @wire and @api I just don't know how I need to approach this change or if it even makes sense to do it with LWC. The visualforce method seems very straightforward to me, but I have no clue on this one. Any help is greatly appreciated.

import { LightningElement } from 'lwc';

export default class CloseButton extends LightningElement {
    record;
    get theRecord() {
        return this.record;
    }
    closeMyCase() {
        
    }
 }
<template>
    <lightning-card>
        <lightning-button
           label="Close Case"
           onclick={closeMyCase}>
        </lightning-button>
    </lightning-card>
</template>

Chatter Feed

Just adding some more updated code after the response. I have the below working by giving me a button on my community page. I can click on the button and get the log the button was clicked and the status is closed, it just has an undefined recordid, not exactly sure why that is. Or If I have gone the wrong way here. The setter doesn't seem to get called.

import { api, LightningElement } from "lwc";

//1. Import reference to the Object and fields
import CASE from '@salesforce/schema/Case';
import CASE_ID from '@salesforce/schema/Case.Id';
import CASE_STATUS from '@salesforce/schema/Case.Status';

//2. Import the named import updateRecord
import { updateRecord } from "lightning/uiRecordApi";

export default class CloseButton3 extends LightningElement {
    
  //3. If I need to update a record then I should have access
  // to the recordId(make sure you use the adaptor @api).    
  @api
  recordId;
  
  status;

  set recordId(value) {
    console.log('I am set');
    this.recordId = value;
}

  closeCase() {
    console.log("I was clicked");
      //4. map the data to the fields
    const fields = {};

    fields[CASE_ID.fieldApiName] = this.recordId;
    fields[CASE_STATUS.fieldApiName] = 'Closed';

    console.log("The record ID is" + fields[CASE_ID.fieldApiName]);
    console.log("The Status is" + fields[CASE_STATUS.fieldApiName]);
        
        //5. Create a config object that had info about fields. 
        //Quick heads up here we are not providing Object API Name
    const recordInput = {
      fields: fields
    };

    console.log("The record input is " + recordInput);

        //6. Invoke the method updateRecord()
    updateRecord(recordInput).then((record) => {
      console.log(record);
    });
  }
}
<template>
    <lightning-card>
        <lightning-button
           label="Close Case"
           onclick={closeCase}>
        </lightning-button>
    </lightning-card>
</template>
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>56.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
    <targetConfig targets="lightningCommunity__Default">
        <property
            name="recordId"
            type="String"
            label="Record Id"
            description="Automatically bind the page's record id to the component variable"
            />
    </targetConfig>
</targetConfigs>
</LightningComponentBundle>

Update with Imperative Apex Call

import { api, LightningElement } from "lwc";
import closeCase from '@salesforce/apex/CloseCaseController.closeCase';

export default class CloseButton4 extends LightningElement {
    theValue = 0;
    @api
    recordId;

    closeCase2() {
        console.log("I was clicked");
        console.log("The record ID is" + this.recordId);
        
        closeCase({ recordId: this.recordId });
        refreshApex(this.recordId);
      }
}
public without sharing class CloseCaseController { 
    @AuraEnabled(cacheable=false) 
    public static void closeCase(Id recordId) {
        Case record = new Case(Id=recordId, Status='Closed'); 
        try {
        update record; 
        }
        catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
    }
    } 
}

1 Answer 1

1

Ordinarily, you'd just create a Quick Action. As a bonus, you don't even need an actual UI or any Apex code at all.


closeCase.js-meta.xml

<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>57.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordAction</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>Action</actionType>
        </targetConfig>
    </targetConfigs>     
</LightningComponentBundle>

closeCase.js

import { LightningElement, api } from 'lwc';
import { updateRecord } from 'lightning/uiRecordApi';
import CASE from '@salesforce/schema/Case';
import CASE_ID from '@salesforce/schema/Case.Id';
import CASE_STATUS from '@salesforce/schema/Case.Status';

export default class CaseClosed extends LightningElement {
    #recordId;
    set recordId(value) {
        this.#recordId = value;
    }
    @api invoke() {
        updateRecord(
            {
                apiName: CASE.objectApiName, 
                fields: { 
                    [CASE_ID.fieldApiName]: this.#recordId, 
                    [CASE_STATUS.fieldApiName]: 'Closed' 
                } 
            }
        );
    }
}

From there, just go to Setup > Object Manager > Cases > Links, Buttons, and Actions, and create a new Quick Action, then go to the Page Layouts section and add the Quick Action to your available buttons, and you're done.

Since updateRecord uses the Lightning Data Service, it should automatically handle errors and refreshing the UI for the user after the case is closed.

15
  • so are you saying I would not need to include a .html file in this case? Would doing it this way get the button outside of the chatter feed? I Included an image above. I don't want the button to be part of the chatter feed, but outside of it as an actual button. That is how I had it with the visualforce page.
    – MarkC5000
    Jan 24, 2023 at 16:36
  • 1
    @MarkC5000 Yes, you'll have to set up your sharing appropriately; using without sharing is not a good idea. If you really need to, though, you could use an @AuraEnabled method on a without sharing class if there's really no other solution.
    – sfdcfox
    Jan 24, 2023 at 19:41
  • 1
    @MarkC5000 Yes, you'd have an Apex class similar to the one you had before: public without sharing class CloseCaseController { @AuraEnabled(cacheable=false) public static void closeCase(Id caseId) { Case record = new Case(Id=caseId, Status='Closed'); update record; } }
    – sfdcfox
    Jan 24, 2023 at 20:03
  • 1
    @MarkC5000 You'd still have a JS file, you'd use the invoke method to call the Apex class. You don't need wire, though, you need to call Apex imperatively.
    – sfdcfox
    Jan 24, 2023 at 20:17
  • 1
    @MarkC5000 try getRecordNotifyChange, since you're using Apex.
    – sfdcfox
    Jan 24, 2023 at 22:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .