+ Start a Discussion
Srinivas223Srinivas223 

Adding a button in Lightning to update records

Hello All,
I have trouble in updating a record using lightning components. I created a ligthning component which shows list of opptys. I have a save button beside every record. When I clicke on Save Record button I am getting errors.
 Here is my code
Controller Class

Public Class ControllerOpportunitiesList{
    
    @AuraEnabled
      public static List<opportunity> getOpportunities() {
        return [SELECT Id, name, stageName,MustSellFirst__c,TradeQuoteValue__c,Current_Offer__c,DemoDate__c,Next_Step__c,Last_Step__c,Targeted_Serial__c,
        CloseDate,Delivery__c, OwnerId,Division_Stage_OpptyName__c, Opportunity_Delivery_Quarter__c, Forecasted__c
         FROM opportunity limit 1000];
      }
    @AuraEnabled
    public static opportunity getOppty(Id opportunityId){
                
        return [SELECT Name, Id FROM opportunity WHERE Id = :opportunityId];
    }
    @AuraEnabled
      public static void saveOpportunity(opportunity opportunity) {
        
        update opportunity;
       // return null;
        }
}
 
<aura:component controller="ControllerOpportunitiesList" implements="force:appHostable, force:lightningQuickActionWithoutHeader,force:hasRecordId">
        <aura:attribute name="Opportunities" type="List" />
        <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
        <aura:iteration items="{!v.Opportunities}" var="opportunity">
                <div class="slds-col slds-m-around--medium"> 
					<th scope="row"><div class="slds-truncate" title="{!opportunity.Division_Stage_OpptyName__c}">{!opportunity.Division_Stage_OpptyName__c}</div></th><br />
                            
           <table class="slds-table slds-table_bordered slds-table_striped slds-table_cell-buffer slds-table_fixed-layout">
          <thead>
            <tr class="slds-text-heading_label">            
              <th scope="col"><div class="fieldLabel" title="Name">Name</div></th>
              <th scope="col"><div class="fieldLabel" title="Stage">StageName</div></th>
              <th scope="col"><div class="fieldLabel"  title="Forecasted">Forecasted</div></th>
              <th scope="col"><div class="fieldLabel" title="MustSell">Must Sell First</div></th>
              <th scope="col"><div class="fieldLabel" title="TradeQuote">Trade Quote</div></th>
              <th scope="col"><div class="fieldLabel" title="Offer">Current Offer</div></th>
                <th scope="col"><div  title="DemoDate">Demo Date</div></th>
                <th scope="col"><div  title="NextStep">Next Step</div></th>
                <th scope="col"><div  title="LastStep">Last Step</div></th>
                <th scope="col"><div  title="Serial">Targeted Serial</div></th>
                <th scope="col"><div  title="CloseDate">Close Date</div></th>
                <th scope="col"><div  title="DeliveryDate">Delivery Date</div></th> 
              	
       <lightning:button label="Save Record" onclick="{!c.saveOpportunity}"/>
              </tr>
          </thead> 
        <tbody>      
          <tr>                     
             <th scope="row">   <ui:inputText aura:id="Name" class="field" 
                                      labelClass="slds-form-element__label"
                                      value="{!opportunity.Name}" required="false"
                                      aura:Id = "OpportunityName" /></th>
             <th scope="row">   <ui:inputText aura:id="StageName" class="field" labelClass="slds-form-element__label"
                                      value="{!opportunity.StageName}"
                                      required="false" aura:Id = "OpportunityStageName" /></th>
             <th scope="row">   <ui:inputText aura:id="FORECASTED" 
                                      class="field"
                                      labelClass="slds-form-element__label"
                                      value="{!opportunity.FORECASTED__C}"
                                      required="false"
                                              aura:Id = "OpportunityFORECASTED" /></th>
              <th scope="row">   <ui:inputText aura:id="MustSell" class="slds-input"
                                      labelClass="slds-form-element__label"
                                      value="{!opportunity.MustSellFirst__c}"
                                      required="false"
                                              aura:Id = "MustSellFirst__c" /></th>
                       <td>                        
                    </td>
                </tr>
              </tbody>
        </table>
      </div>
    </aura:iteration>
</aura:component>
 
Controller 

({
	doInit: function(component, event, helper) {        
		 helper.getOpportunitiesList(component);      
	},          
	saveOpportunity : function(c, e, h) {
		h.updateCheck_helper(c,e,h);
	}    
})
({
	getOpportunitiesList: function(component) {
        var action = component.get('c.getOpportunities');
        // Set up the callback
        var self = this;
        action.setCallback(this, function(actionResult) {
         component.set('v.Opportunities', actionResult.getReturnValue());
        });
        $A.enqueueAction(action);
      },
    doInit : function(component, event, helper) {
        //get inventory record Id
        var action = component.get('c.getOppty');
        action.setParams({"opportunityId" : component.get("v.recordId")});
 
        //configure action handler
        action.setCallback(this, function(response){
            var state = response.getState();
            if(state === "SUCCESS"){
                component.set("v.opportunity", response.getReturnValue());
            }else{
                console.log('Problem getting inventory, response state : '+state);
            }
        });
        $A.enqueueAction(action);
    },
    updateCheck_helper : function(c,e,h) {
       // alert('sdfsd');
		var save_action = c.get("c.saveOpportunity");
    	save_action.setParams({"opportunity": component.get("v.opportunity")});
        $A.enqueueAction(save_action);
	}
})

I appreciate your help.
Thank you!
 
Best Answer chosen by Srinivas223
Khan AnasKhan Anas (Salesforce Developers) 
Hi Srinivas,

Please try the below code, it is working fine. Kindly modify the code as per your requirement.

Application:
<aura:application extends="force:slds">
    <c:UpdateInput />
</aura:application>

Component:
<aura:component controller="UpdateInputController"
                implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >
    
    <aura:attribute name="Opportunities" type="List" />
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:handler event="force:refreshView" action="{!c.doInit}" />
    
    <div class="slds-col slds-m-around--medium">            
        <table class="slds-table slds-table_bordered slds-table_striped slds-table_cell-buffer slds-table_fixed-layout">
            <thead>
                <tr class="slds-text-heading_label">            
                    <th scope="col"><div class="fieldLabel" title="Name">Name</div></th>
                    <th scope="col"><div class="fieldLabel" title="Amount">Amount</div></th>                                               
                </tr>
            </thead> 
            <tbody>    
                <aura:iteration items="{!v.Opportunities}" var="opp" >
                    <tr>                     
                        <th scope="row">   
                            <ui:inputText class="field" 
                                          labelClass="slds-form-element__label"
                                          value="{!opp.Name}"
                                          aura:id = "OpportunityName" /></th>
                        <th scope="row">   
                            <ui:inputText class="field" 
                                          labelClass="slds-form-element__label"
                                          value="{!opp.Amount}" 
                                          aura:id = "OpportunityAmount" /></th>
                        <th scope="row">
                            <lightning:button value="{!opp}" 
                                              label="Save Record" 
                                              onclick="{!c.saveOpportunity}"/>
                        </th>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>    
</aura:component>

Controller:
({
	doInit : function (component, event, helper) {
        helper.getOpportunitiesList(component, event);
    },
    
    saveOpportunity : function (component, event, helper) {
        helper.updateHelper(component, event);
    }
})

Helper:
({
	getOpportunitiesList : function(component, event) {
        var action = component.get('c.getOpportunities');
        // Set up the callback
        action.setCallback(this, function(actionResult) {
            component.set('v.Opportunities', actionResult.getReturnValue());
        });
        $A.enqueueAction(action);
    },
    
    updateHelper : function(component, event) {
        var opp = event.getSource().get("v.value")
        console.log('opp-- > ' + JSON.stringify(opp));
        
        var action1 = component.get("c.saveOpp");
        action1.setParams({ "op" : opp });
        action1.setCallback(this, function(resp){
            var state = resp.getState();
            if(state === "SUCCESS"){
                $A.get('e.force:refreshView').fire();
                console.log('server- > ' + resp.getReturnValue());
                alert('Success');
            }
            else if (state === "ERROR") {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " + 
                                 errors[0].message);
                    }
                } 
                else {
                    console.log(resp.getReturnValue());
                }
            }
        });
        $A.enqueueAction(action1);
    }
})

Server Controller:
public class UpdateInputController {
    
    @AuraEnabled
    public static Opportunity saveOpp(Opportunity op) {
        update op;
        return op;
    }

    @AuraEnabled
    public static List<Opportunity> getOpportunities() {
        return [SELECT Id, Name, Amount, CloseDate FROM Opportunity LIMIT 100];
    }
}


I hope it helps you.

Kindly let me inform if it helps you and close your query by marking it as solved so that it can help others in future.

Thanks and Regards,
Khan Anas​

All Answers

Khan AnasKhan Anas (Salesforce Developers) 
Hi Srinivas,

Please try the below code, it is working fine. Kindly modify the code as per your requirement.

Application:
<aura:application extends="force:slds">
    <c:UpdateInput />
</aura:application>

Component:
<aura:component controller="UpdateInputController"
                implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >
    
    <aura:attribute name="Opportunities" type="List" />
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:handler event="force:refreshView" action="{!c.doInit}" />
    
    <div class="slds-col slds-m-around--medium">            
        <table class="slds-table slds-table_bordered slds-table_striped slds-table_cell-buffer slds-table_fixed-layout">
            <thead>
                <tr class="slds-text-heading_label">            
                    <th scope="col"><div class="fieldLabel" title="Name">Name</div></th>
                    <th scope="col"><div class="fieldLabel" title="Amount">Amount</div></th>                                               
                </tr>
            </thead> 
            <tbody>    
                <aura:iteration items="{!v.Opportunities}" var="opp" >
                    <tr>                     
                        <th scope="row">   
                            <ui:inputText class="field" 
                                          labelClass="slds-form-element__label"
                                          value="{!opp.Name}"
                                          aura:id = "OpportunityName" /></th>
                        <th scope="row">   
                            <ui:inputText class="field" 
                                          labelClass="slds-form-element__label"
                                          value="{!opp.Amount}" 
                                          aura:id = "OpportunityAmount" /></th>
                        <th scope="row">
                            <lightning:button value="{!opp}" 
                                              label="Save Record" 
                                              onclick="{!c.saveOpportunity}"/>
                        </th>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>    
</aura:component>

Controller:
({
	doInit : function (component, event, helper) {
        helper.getOpportunitiesList(component, event);
    },
    
    saveOpportunity : function (component, event, helper) {
        helper.updateHelper(component, event);
    }
})

Helper:
({
	getOpportunitiesList : function(component, event) {
        var action = component.get('c.getOpportunities');
        // Set up the callback
        action.setCallback(this, function(actionResult) {
            component.set('v.Opportunities', actionResult.getReturnValue());
        });
        $A.enqueueAction(action);
    },
    
    updateHelper : function(component, event) {
        var opp = event.getSource().get("v.value")
        console.log('opp-- > ' + JSON.stringify(opp));
        
        var action1 = component.get("c.saveOpp");
        action1.setParams({ "op" : opp });
        action1.setCallback(this, function(resp){
            var state = resp.getState();
            if(state === "SUCCESS"){
                $A.get('e.force:refreshView').fire();
                console.log('server- > ' + resp.getReturnValue());
                alert('Success');
            }
            else if (state === "ERROR") {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " + 
                                 errors[0].message);
                    }
                } 
                else {
                    console.log(resp.getReturnValue());
                }
            }
        });
        $A.enqueueAction(action1);
    }
})

Server Controller:
public class UpdateInputController {
    
    @AuraEnabled
    public static Opportunity saveOpp(Opportunity op) {
        update op;
        return op;
    }

    @AuraEnabled
    public static List<Opportunity> getOpportunities() {
        return [SELECT Id, Name, Amount, CloseDate FROM Opportunity LIMIT 100];
    }
}


I hope it helps you.

Kindly let me inform if it helps you and close your query by marking it as solved so that it can help others in future.

Thanks and Regards,
Khan Anas​
This was selected as the best answer
Khan AnasKhan Anas (Salesforce Developers) 
Hi Srinivas,

Also note that the Apex method's name was the same as the Javascript controller method's name. So when executing var action = component.get("c.saveOpportunity"); it created a conflict, and the Javascript method was called twice, but the apex was never called.

A Javascript method name in a Client Controller can never be the same name in a Server Controller.

From documentation (https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_actions_call.htm) :
"Use unique names for client-side and server-side actions in a component. A JavaScript function (client-side action) with the same name as an Apex method (server-side action ) can lead to hard-to-debug issues. In debug mode, the framework logs a browser console warning about the clashing client-side and server-side action names".


I hope it helps you.

Kindly mark this as solved if the information was helpful.

Thanks and regards,
Khan Anas
Srinivas223Srinivas223
Thank You Khan. It worked perfect!
I added more columns to the layout and is compatible to desktop where i can move left and right to see all fields. The same is not happening on mobile. 
Is there anyway you know to fix this?

I appreciate your help.
Khan AnasKhan Anas (Salesforce Developers) 
Hi Srinivas,

You can use ui:scrollerWrapper that enables native scrolling of Lightning Components in Salesforce app as well as in Lightning Desktop.

Please refer below link for more details.

https://developer.salesforce.com/docs/component-library/bundle/ui:scrollerWrapper/documentation

https://www.lightningdesignsystem.com/utilities/scrollable/


Thanks and Regards,
Khan Anas