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
Robert Wambold 10Robert Wambold 10 

Lightning Components error "Unable to find action 'getCaseComments' on the controller of c:CaseCommentList"

Hello All,

Taking a shot at my first Lighting Component App and cannot resolve my #^&!# error. The purpose of my app is to display CaseComments related to a Case. When I attempt to Preview my app get the following error:

User-added image

*** Can Someone please help me find my error? ***

Thanks in advance.

Robert

Here's my code:

CaseCommentListController.cls

// Apex Controller for CaseComment List Lightning Component
public class CaseCommentListController {
  
    @AuraEnabled
    public static List<CaseComment> getCaseCommentsList(List<Id> parentIds) {
      // Getting the list of casecomments from where Id is in parentIds
    List<CaseComment> casecommentList = [SELECT Id, CommentBody, ParentId FROM CaseComment WHERE ParentId in :parentIds];
    // Returning the casecomment list
        return casecommentList;
    }

    @AuraEnabled
    public static Map<String,String> saveCaseCommentList(List<CaseComment> casecommentList) {
      // Forming a  string map to return response
        Map<String,String> resultMap = new Map<String,String>();
        // Adding try catch for exception handling
        try {
          // Updating the CaseComment List
            update casecommentList;
            // Setting the success status and message in resultMap
            resultMap.put('status', 'success');
          resultMap.put('message', 'CaseComments Updated Successfully');        
      }
      catch(Exception e) {
            // Setting the error status and message in resultMap
            resultMap.put('status', 'error');
      resultMap.put('message',e.getMessage());
      }
      // Returning the result string map
        return resultMap;
    }
    
    @AuraEnabled
    public static Map<String,String> deleteCaseCommentList(List<Id> casecommentIds) {
        //Fetching CaseComments
        List<CaseComment> casecommentsToDelete = [SELECT Id FROM CaseComment WHERE Id in :casecommentIds];
        // Forming a  string map to return response
        Map<String,String> resultMap = new Map<String,String>();
        // Adding try catch for exception handling
        try {
          // Deleting the CaseComments
            delete casecommentsToDelete;
            // Setting the success status and message in resultMap
            resultMap.put('status', 'success');
          resultMap.put('message', 'CaseComments Deleted Successfully');        
      }
      catch(Exception e) {
            // Setting the error status and message in resultMap
            resultMap.put('status', 'error');
      resultMap.put('message',e.getMessage());
      }
      // Returning the result string map
        return resultMap;                
    }

    @AuraEnabled
    public static Map<String, String> createCaseCommentRecord(CaseComment newCaseComment) {
        // Forming a  string map to return response
        Map<String,String> resultMap = new Map<String,String>();
        // Adding try catch for exception handling
        try {
            // Inserting the CaseComment
            insert newCaseComment;
            // Setting the success status and message in resultMap
            resultMap.put('status', 'success');
            resultMap.put('message', 'CaseComment Inserted Successfully');        
        }
        catch(Exception e) {
            // Setting the error status and message in resultMap
            resultMap.put('status', 'error');
            resultMap.put('message',e.getMessage());
        }
        // Returning the result string map
        return resultMap;        
    }
}

CaseCommentListApp.app

<!-- Application to call CaseCommentList component -->
<aura:application extends="force:slds" >
	<!-- force:slds extended to apply lightning design system styling and passed in the record Id -->
    <c:CaseCommentList recordId="5000y00001dWMmQAAW" />
</aura:application>

CaseCommentListAppController.js

({
    // Function called on initial page loading to get casecomment list from server
    getCaseCommentsList : function(component, event, helper) { 
        // Helper function - fetchCaseComments called for interaction with server
		helper.fetchCaseComments(component, event, helper);
	},

    // Function used to create a new CaseComment
    newCaseComment: function(component, event, helper) {
        // Global event force:createRecord is used
        var createCaseComment = $A.get("e.force:createRecord");
        // Parameters like apiName and defaultValues are set
        createCaseComment.setParams({
            "entityApiName": "CaseComment",
            "defaultFieldValues": {
                "ParentId": component.get("v.recordId")
            }
        });
        // Event fired and new casecomment dialog open
        createCaseComment.fire();
    },

    // Function used to update the casecomments
    editCaseComments: function(component, event, helper) {
        // Getting the button element
        var btn = event.getSource();
        // Getting the value in the name attribute
        var name = btn.get('v.name');
        // Getting the record view form and the record edit form elements
        var recordViewForm = component.find('recordViewForm');
        var recordEditForm = component.find('recordEditForm'); 
        // If button is edit
        if(name=='edit') {
            // Hiding the recordView Form and making the recordEdit form visible
            $A.util.addClass(recordViewForm,'formHide');
            $A.util.removeClass(recordEditForm,'formHide');
            // Changing the button name and label
            btn.set('v.name','save');
            btn.set('v.label','Save');
        }
        else if(name=='save') {
            // Calling saveCaseCommentList if the button is save
            helper.saveCaseCommentList(component, event, helper);
        }
    }
})

CaseCommentListAppHelper.js

({
	helperMethod : function() {
		
	}
})

CaseCommentListApp.css

.THIS {
}
.THIS .formHide {
	display: none;
}

CaseCommentListCmp.cmp

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes" controller="CaseCommentListController" access="global">
    <!-- Handler to call function when page is loaded initially -->
    <aura:handler name="init" action="{!c.getCaseComments}" value="{!this}" />
    <!-- List of casecomments stored in attribute -->
    <aura:attribute name="casecommentList" type="List" />
    <!-- New CaseComment Object -->
    <aura:attribute name="casecomment" type="CaseComment"
    default="{
        'SObjectType': 'CaseComment', 'CommentBody': ''
    }">            
    </aura:attribute>
    <!-- Method to validate new casecomment -->
    <aura:method name="validateCaseComment" action="{!c.validateCaseComment}" />
    <!-- Lightning card to show casecomments -->
    <lightning:card title="CaseComments">
        <!-- Body of lightning card starts here -->
        <p class="slds-p-horizontal_small">
            <!-- Aura iteration to iterate list, similar to apex:repeat -->
            <div aura:id="recordViewForm">
                <aura:iteration items="{!v.casecommentList}" var="casecomment">
                    <!-- recordViewForm to view the record -->
                    <lightning:recordViewForm recordId="{!casecomment.Id}" objectApiName="CaseComment">
                        <div class="slds-box slds-theme_default">
                            <!-- inputfield checkbox used to check wether to delete the casecomment or not -->
                            <lightning:input type="checkbox" value="{!casecomment.Id}" label="Mark for Deletion" aura:id="deleteCaseComment" />
                            <br />
                            <!-- outputfield used to output the record field data inside recordViewForm -->
                            <lightning:outputField fieldName="CommentBody" />
                        </div>
                    </lightning:recordViewForm>
                    <!-- Line break between two records -->
                    <br />
                </aura:iteration>
            </div>
            <div aura:id="recordEditForm" class="formHide">
                <aura:iteration items="{!v.casecommentList}" var="casecomment">
                    <div class="slds-box slds-theme_default">
                        <!-- inputfield used to update the record field data -->
                        <!-- Validation added -->
                        <lightning:input aura:id="fieldToValidate" value="{!casecomment.CommentBody}" messageWhenValueMissing="Comment is Mandatory" required="true"/>
                    </div>
                    <br />
                    <!-- Line break between two records -->
                </aura:iteration>
            </div>
        </p>
        <!-- Lightning card actions -->
        <aura:set attribute="actions">
            <!-- New casecomment modal button added -->
            <lightning:button name="casecommentModal" label="New CaseComment" onclick="{!c.openModal}" />
            <!-- Delete button added -->
            <lightning:button variant="destructive" label="Delete" onclick="{!c.deleteCaseComments}" />
            <!-- New button added -->
            <lightning:button label="New" onclick="{!c.newCaseComment}" />
            <!-- Edit/Save button added -->
            <lightning:button variant="brand" label="Edit" name="edit" onclick="{!c.editCaseComments}" />
        </aura:set>
    </lightning:card>
    <!-- CaseComments Modal Section -->
    <div>
        <section aura:id="casecommentModal" role="dialog" tabindex="-1" aria-labelledby="casecommentModalHeading" aria-modal="true" aria-describedby="casecommentModalBody" class="slds-modal">
            <!-- Modal Container -->
            <div class="slds-modal__container">
                <!-- Modal Header ( consists of close button and heading of modal ) -->
                <header class="slds-modal__header">
                    <lightning:buttonIcon class="slds-modal__close" alternativeText="Close" iconName="utility:close" onclick="{!c.closeModal}" variant="bare-inverse" size="large"></lightning:buttonIcon>
                    <h2 id="casecommentModalHeading" class="slds-text-heading_medium slds-hyphenate">New CaseComment</h2>
                </header>
                <!-- Modal Body ( consists of form ) -->
                <div class="slds-modal__content slds-p-around_medium" id="casecommentModalBody">
                    <!-- Validation added -->
                    <lightning:input aura:id="formFieldToValidate" label="Comment" messageWhenValueMissing="Comment is Mandatory" required="true" value="{!v.casecomment.CommentBody}" />
                </div>
                <!-- Modal Footer ( consists of cancel and save buttons ) -->
                <footer class="slds-modal__footer">
                    <lightning:button onclick="{!c.closeModal}" variant="neutral">Cancel</lightning:button>
                    <lightning:button onclick="{!c.createCaseComment}" variant="brand" >Save</lightning:button>
                </footer>
            </div>
        </section>
        <!-- Modal Backdrop -->
        <div aura:id="casecommentModalBackdrop" class="slds-backdrop"></div>
    </div>
</aura:component>

CaseCommentListCmpController.js

({
    // Function called on initial page loading to get casecomment list from server
	getCaseCommentsList : function(component, event, helper) {
        // Helper function - fetchCaseComments called for interaction with server
		helper.fetchCaseComments(component, event, helper);
	},

    // Function used to create a new casecomment
    newcasecomment: function(component, event, helper) {
        // Global event force:createRecord is used
        var createcasecomment = $A.get("e.force:createRecord");
        // Parameters like apiName and defaultValues are set
        createcasecomment.setParams({
            "entityApiName": "casecomment",
            "defaultFieldValues": {
                "ParentId": component.get("v.recordId")
            }
        });
        // Event fired and new casecomment dialog open
        createcasecomment.fire();
    },

    // Function used to update the casecomments
    editCaseComments: function(component, event, helper) {
        // Getting the button element
        var btn = event.getSource();
        // Getting the value in the name attribute
        var name = btn.get('v.name');
        // Getting the record view form and the record edit form elements
        var recordViewForm = component.find('recordViewForm');
        var recordEditForm = component.find('recordEditForm'); 
        // If button is edit
        if(name=='edit') {
            // Hiding the recordView Form and making the recordEdit form visible
            $A.util.addClass(recordViewForm,'formHide');
            $A.util.removeClass(recordEditForm,'formHide');
            // Changing the button name and label
            btn.set('v.name','save');
            btn.set('v.label','Save');
        }
        else if(name=='save') {
            // Getting the edit form fields to validate
            var casecommentFields = component.find("fieldToValidate");
            // Initialize the counter to zero - used to check validity of fields
            var blank=0;
            // If there are more than 1 fields
            if(casecommentFields.length!=undefined) {
                // Iterating all the fields
                var allValid = casecommentFields.reduce(function (validSoFar, inputCmp) {
                // Show help message if single field is invalid
                inputCmp.showHelpMessageIfInvalid();
                // return whether all fields are valid or not
                return validSoFar && inputCmp.get('v.validity').valid;
                }, true);
                // If all fields are not valid increment the counter
                if (!allValid) {
                    blank++;
                }
            } else {
                // If there is only one field, get that field and check for validity (true/false)
                var allValid = casecommentFields;
                // If field is not valid, increment the counter
                if (!allValid.get('v.validity').valid) {
                    blank++;
                }
            }
            // Call the helper method only when counter is 0
            if(blank==0) {
                // Calling saveCaseComments if the button is save
                helper.saveCaseComments(component, event, helper);                
            }
        }
    },
    
    // Function used to delete the casecomments
    deleteCaseComments: function(component, event, helper) {
        // Calling removeCaseComments Helper Function
        helper.removeCaseComments(component, event, helper);
    },

    // Function used to open the casecomment modal
    openModal: function(component, event, helper) {
        var modal = component.find("casecommentModal");
        var modalBackdrop = component.find("casecommentModalBackdrop");
        $A.util.addClass(modal,"slds-fade-in-open");
        $A.util.addClass(modalBackdrop,"slds-backdrop_open");
    },

    // Function used to close the casecomment modal
    closeModal: function(component, event, helper) {
        var modal = component.find("casecommentModal");
        var modalBackdrop = component.find("casecommentModalBackdrop");
        $A.util.removeClass(modal,"slds-fade-in-open");
        $A.util.removeClass(modalBackdrop,"slds-backdrop_open");
    },

    // Function used to create new casecomment
    createcasecomment: function(component, event, helper) {
        var iscasecommentValid = component.validatecasecomment(component, event, helper);
        if(iscasecommentValid) {
           helper.insertcasecomment(component, event, helper);
        }
    },

    // Function to validate new casecomment - Aura method used for the same
    validatecasecomment: function(component, event, helper) {
        // Getting all fields and iterate them to check for validity
        var allValid = component.find('formFieldToValidate').reduce(function (validSoFar, inputCmp) {
            // Show help message if single field is invalid
            inputCmp.showHelpMessageIfInvalid();
            // Get the name of each field
            var name = inputCmp.get('v.name');
            // Check if name is emailField
            if(name=='emailField') {
                // Getting the value of that field
                var value = inputCmp.get('v.value');
                // If value is not equal to robert.wambold@almacgroup.com, add custom validation
                if(value != 'robert.wambold@almacgroup.com') {
                    // Focus on that field to make custom validation work
                    inputCmp.focus();
                    // Setting the custom validation
                    inputCmp.set('v.validity', {valid:false, badInput :true});
                }                
            }
            // Returning the final result of validations
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // Returning Validate casecomment result in boolen
        return allValid;
    }

})

CaseCommentListCmpHelper.js

({
    // Function to fetch data from server called in initial loading of page
	fetchCaseComments : function(component, event, helper) {
        // Assign server method to action variable
        var action = component.get("c.getCaseCommentList");
        // Getting the parent id from page
        var parentId = component.get("v.recordId");
        // Setting parameters for server method
        action.setParams({
            parentIds: parentId
        });
        // Callback function to get the response
        action.setCallback(this, function(response) {
            // Getting the response state
            var state = response.getState();
            // Check if response state is success
            if(state === 'SUCCESS') {
                // Getting the list of casecomments from response and storing in js variable
                var casecommentList = response.getReturnValue();
                // Set the list attribute in component with the value returned by function
                component.set("v.casecommentList",casecommentList);
            }
            else {
                // Show an alert if the state is incomplete or error
                alert('Error in getting data');
            }
        });
        // Adding the action variable to the global action queue
        $A.enqueueAction(action);
	},

    // Function to update the casecomments on server
    saveCaseComments: function(component, event, helper) {
        // Getting the casecomment list from lightning component
        var casecommentList = component.get("v.casecommentList");
        // Getting the recordViewForm and recordEditForm component
        var recordViewForm = component.find('recordViewForm');
        var recordEditForm = component.find('recordEditForm'); 
        // Initializing the toast event to show toast
        var toastEvent = $A.get('e.force:showToast');
        // Defining the action to save casecomment List ( will call the saveCaseCommentList apex controller )
        var saveAction = component.get("c.saveCaseCommentList");
        // setting the params to be passed to apex controller
        saveAction.setParams({ casecommentList: casecommentList });
        // callback action on getting the response from server
        saveAction.setCallback(this, function(response) {
            // Getting the state from response
            var state = response.getState();
            if(state === 'SUCCESS') {
                // Getting the response from server
                var dataMap = response.getReturnValue();
                // Checking if the status is success
                if(dataMap.status=='success') {
                    // Remove the formHide class
                    $A.util.removeClass(recordViewForm,'formHide');
                    // Add the formHide class
                    $A.util.addClass(recordEditForm,'formHide');
                    // Getting the button element
                    var btn = event.getSource();
                    // Setting the label and name of button back to edit
                    btn.set('v.name','edit');
                    btn.set('v.label','Edit');
                    // Setting the success toast which is dismissable ( vanish on timeout or on clicking X button )
                    toastEvent.setParams({
                        'title': 'Success!',
                        'type': 'success',
                        'mode': 'dismissable',
                        'message': dataMap.message
                    });
                    // Fire success toast event ( Show toast )
                    toastEvent.fire();            
                }
                // Checking if the status is error 
                else if(dataMap.status=='error') {
                    // Setting the error toast which is dismissable ( vanish on timeout or on clicking X button )
                    toastEvent.setParams({
                        'title': 'Error!',
                        'type': 'error',
                        'mode': 'dismissable',
                        'message': dataMap.message
                    });
                    // Fire error toast event ( Show toast )
                    toastEvent.fire();                
                }
            }
            else {
                // Show an alert if the state is incomplete or error
                alert('Error in getting data');
            }
        });
        $A.enqueueAction(saveAction);
    }    
})

CaseCommentListCmp.css

.THIS {
}
.THIS .formHide {
	display: none;
}
 

*** Thanks again for helping !!! ***

 

 

Best Answer chosen by Robert Wambold 10
Devi ChandrikaDevi Chandrika (Salesforce Developers) 
Hi Robert,
You are using wrong method name .In the CaseCommentListCmp.cmp init handler the action is getCaseComments.But there is no getCaseComments methods in 
CaseCommentListCmpController.js.You have to call getCaseCommentsList in init handler of CaseCommentListCmp.cmp

Try this one

CaseCommentListCmp.cmp
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes" controller="CaseCommentListController" access="global">
    <!-- Handler to call function when page is loaded initially -->
    <aura:handler name="init" action="{!c.getCaseCommentsList}" value="{!this}" />
    <!-- List of casecomments stored in attribute -->
    <aura:attribute name="casecommentList" type="List" />
    <!-- New CaseComment Object -->
    <aura:attribute name="casecomment" type="CaseComment"
    default="{
        'SObjectType': 'CaseComment', 'CommentBody': ''
    }">            
    </aura:attribute>
    <!-- Method to validate new casecomment -->
    <aura:method name="validateCaseComment" action="{!c.validateCaseComment}" />
    <!-- Lightning card to show casecomments -->
    <lightning:card title="CaseComments">
        <!-- Body of lightning card starts here -->
        <p class="slds-p-horizontal_small">
            <!-- Aura iteration to iterate list, similar to apex:repeat -->
            <div aura:id="recordViewForm">
                <aura:iteration items="{!v.casecommentList}" var="casecomment">
                    <!-- recordViewForm to view the record -->
                    <lightning:recordViewForm recordId="{!casecomment.Id}" objectApiName="CaseComment">
                        <div class="slds-box slds-theme_default">
                            <!-- inputfield checkbox used to check wether to delete the casecomment or not -->
                            <lightning:input type="checkbox" value="{!casecomment.Id}" label="Mark for Deletion" aura:id="deleteCaseComment" />
                            <br />
                            <!-- outputfield used to output the record field data inside recordViewForm -->
                            <lightning:outputField fieldName="CommentBody" />
                        </div>
                    </lightning:recordViewForm>
                    <!-- Line break between two records -->
                    <br />
                </aura:iteration>
            </div>
            <div aura:id="recordEditForm" class="formHide">
                <aura:iteration items="{!v.casecommentList}" var="casecomment">
                    <div class="slds-box slds-theme_default">
                        <!-- inputfield used to update the record field data -->
                        <!-- Validation added -->
                        <lightning:input aura:id="fieldToValidate" value="{!casecomment.CommentBody}" messageWhenValueMissing="Comment is Mandatory" required="true"/>
                    </div>
                    <br />
                    <!-- Line break between two records -->
                </aura:iteration>
            </div>
        </p>
        <!-- Lightning card actions -->
        <aura:set attribute="actions">
            <!-- New casecomment modal button added -->
            <lightning:button name="casecommentModal" label="New CaseComment" onclick="{!c.openModal}" />
            <!-- Delete button added -->
            <lightning:button variant="destructive" label="Delete" onclick="{!c.deleteCaseComments}" />
            <!-- New button added -->
            <lightning:button label="New" onclick="{!c.newCaseComment}" />
            <!-- Edit/Save button added -->
            <lightning:button variant="brand" label="Edit" name="edit" onclick="{!c.editCaseComments}" />
        </aura:set>
    </lightning:card>
    <!-- CaseComments Modal Section -->
    <div>
        <section aura:id="casecommentModal" role="dialog" tabindex="-1" aria-labelledby="casecommentModalHeading" aria-modal="true" aria-describedby="casecommentModalBody" class="slds-modal">
            <!-- Modal Container -->
            <div class="slds-modal__container">
                <!-- Modal Header ( consists of close button and heading of modal ) -->
                <header class="slds-modal__header">
                    <lightning:buttonIcon class="slds-modal__close" alternativeText="Close" iconName="utility:close" onclick="{!c.closeModal}" variant="bare-inverse" size="large"></lightning:buttonIcon>
                    <h2 id="casecommentModalHeading" class="slds-text-heading_medium slds-hyphenate">New CaseComment</h2>
                </header>
                <!-- Modal Body ( consists of form ) -->
                <div class="slds-modal__content slds-p-around_medium" id="casecommentModalBody">
                    <!-- Validation added -->
                    <lightning:input aura:id="formFieldToValidate" label="Comment" messageWhenValueMissing="Comment is Mandatory" required="true" value="{!v.casecomment.CommentBody}" />
                </div>
                <!-- Modal Footer ( consists of cancel and save buttons ) -->
                <footer class="slds-modal__footer">
                    <lightning:button onclick="{!c.closeModal}" variant="neutral">Cancel</lightning:button>
                    <lightning:button onclick="{!c.createCaseComment}" variant="brand" >Save</lightning:button>
                </footer>
            </div>
        </section>
        <!-- Modal Backdrop -->
        <div aura:id="casecommentModalBackdrop" class="slds-backdrop"></div>
    </div>
</aura:component>

Hope this helps you
If this helps kindly mark it as solved so that it may help others in future.

Thanks and Regards