4

I created a Lightning Component to save an account, which loads a particular account based on the URL parameter (id).

I am having a trouble with saving the record with an event, the problem is I cannot see a mechanism to call the apex method.

Could someone explain me where do I need to call my apex method? whats wrong with below code.

I ran through few samples and none of them aren't clear for me.

ref1 ref2 ref3

Thanks in advance

Please see the code below;

EVENT COMPONENT

<aura:event type="COMPONENT" description="Event template" >
        <aura:attribute name="account" type="Account" />
</aura:event>

MAIN COMPONENT (register event and call to controller)

<aura:component controller="AccountsController">
  <aura:registerEvent name="SaveAccount" type="c:SaveAccountEvent"/> 
  <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
  <aura:attribute name="account" type="Account" />
    <div class="slds-text-heading--medium slds-p-top--x-small slds-p-bottom--x-small">Edit Account</div>
    <div class="slds-form-element">
        <label class="slds-form-element__label" for="name">Name</label>
        <div class="slds-form-element__control">
            <ui:inputText aura:id="name" value="{!v.account.Name}" class="slds-input" placeholder="..." />
        </div>
    </div>
    <div class="slds-form-element">
        <label class="slds-form-element__label" for="website">Website</label>
        <div class="slds-form-element__control">
            <ui:inputText aura:id="website" value="{!v.account.Website}" class="slds-input" placeholder="..." />
        </div>
    </div>
    <div class="slds-form-element">
        <label class="slds-form-element__label" for="Id">Id</label>
        <div class="slds-form-element__control">
            <ui:inputText aura:id="Id" value="{!v.account.Id}" class="slds-input" placeholder="..." />
        </div>
    </div>
    <div class="slds-col slds-no-flex slds-align-bottom">
        <div class="slds-button-group" role="group">
            <button class="slds-button slds-button--neutral" onclick="{!c.fireSaveEvent}">Save</button>
        </div>
    </div>
</aura:component>

CLIENT-SIDE CONTROLLER

fireSaveEvent : function(cmp, ev) {
    var appEvent = cmp.getEvent("SaveAccountDetails");
    appEvent.setParams({ "account": cmp.get("v.account") });
    appEvent.fire();
}

APEX METHOD

@AuraEnabled
global static Account saveAccountDetails(Account account) {
    System.debug(' HASA SAVED ACCOUNT '+account);
    Account updatedAccount = [ SELECT Id, Name,ShippingCity, Website
                              FROM Account
                              WHERE Id = :account.id ];


    updatedAccount.Website = account.Website;
    update updatedAccount;
    return updatedAccount;

}
3
  • have you added <aura:component controller="your Apex CLass Name" /> ?
    – Ratan Paul
    Commented Nov 30, 2015 at 4:51
  • @Ratan: yes I have my cls name in the controller attribute, I updated the component code in the post. Thanks
    – Hasantha
    Commented Nov 30, 2015 at 5:19
  • check my ans. You can't call a apex function directly you need to use aura:handler for your event that will call js function from there you can call apex class function.
    – Ratan Paul
    Commented Nov 30, 2015 at 6:03

3 Answers 3

2

First check that you given controller name in aura:component

<aura:component controller="SimpleServerSideController">
    <aura:attribute name="firstName" type="String" default="world"/>
    <ui:button label="Call server" press="{!c.echo}"/>
</aura:component>

After this in your controller (Javascript) call your action method

({
    "echo" : function(cmp) {
        // create a one-time use instance of the serverEcho action
        // in the server-side controller
        **var action = cmp.get("c.serverEcho");**
        action.setParams({ firstName : cmp.get("v.firstName") });

        // Create a callback that is executed after 
        // the server-side action returns
        action.setCallback(this, function(response) {
            var state = response.getState();
            // This callback doesn’t reference cmp. If it did,
            // you should run an isValid() check
            //if (cmp.isValid() && state === "SUCCESS") {
            if (state === "SUCCESS") {
                // Alert the user with the value returned 
                // from the server
                alert("From server: " + response.getReturnValue());

                // You would typically fire a event here to trigger 
                // client-side notification that the server-side 
                // action is complete
            }
            //else if (cmp.isValid() && state === "ERROR") {
            else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " + 
                                 errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
        });

        // optionally set abortable flag here

        // A client-side action could cause multiple events, 
        // which could trigger other events and 
        // other server-side action calls.
        // $A.enqueueAction adds the server-side action to the queue.
        $A.enqueueAction(action);
    }
})

Please check these two things and it will solve your problem.

Reference.

3
  • @Thushar: Can't we use <aura:event /> tag? is it not capable of making a server side call?
    – Hasantha
    Commented Nov 30, 2015 at 5:22
  • @ahtnasah.li you cannot directly call the controller method from here. from your Javascript when you fire the vent then you can call the methods. Same as given in above code sample. Commented Nov 30, 2015 at 5:28
  • Indeed the Apex method is surfaced via the action object with callback if necessary. There is no direct-to-event binding. Very different if you are used to traditional VF controller action binding. A lot more like RemoteAction Apex for Visualforce.
    – pchittum
    Commented Nov 30, 2015 at 15:26
1

In the Lightning Component framework, events are fired from JavaScript controller actions. Events can contain attributes that can be set before the event is fired and read when the event is handled.

So looks you can't directly call the apex class method. For that you need to call a JS function using aura:handler. check out this example.

<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<aura:registerEvent name="SaveAccount" type="c:SaveAccountEvent"/>   
<aura:handler name="SaveAccount" action="{!c.fireSaveEvent }"/>

So init method first called then you can get some value from apex class and store into the event params and after that you can fire the event so when you fire the event that will call the another method i.e. fireSaveEvent In lightning controller

init: function(cmp, ev) {
   var action = component.get("c.firstmethod");
    action.setParams({"name" : 'Test'});

    action.setCallback(this, function(response){
        var state = response.getState();

        //added later
        if (state === "SUCCESS") {

               var cmpEvent = component.getEvent("SaveAccount");
               cmpEvent.setParams({"account" : state.getReturnValue(); });
               cmpEvent.fire(); //so it will fire your event and call fireSaveEvent function 
            }
        });  
        }else if(state === "ERROR"){
            console.error(response.getError()[0].message);
        }

   });
   $A.enqueueAction(action);

}
,
fireSaveEvent : function(cmp, ev) {
   var action = component.get("c.fetchAllTasks");
    action.setParams({"account" : cmp.get("v.account")});

    action.setCallback(this, function(response){
        var state = response.getState();

        //added later
        if (state === "SUCCESS") {

               //here use any attribute to store your values.
            }
        });  
        }else if(state === "ERROR"){
            console.error(response.getError()[0].message);
        }

   });
   $A.enqueueAction(action);

}
1
  • Firing a second event from init is a bit overkill. In this instance, you only need handle the init event here and call the action directly from the handler. Init is a built in event that automatically fires as part of the component lifecycle.
    – pchittum
    Commented Nov 30, 2015 at 15:30
0

You are no where handling your event in your code, you have just registered the event : <aura:registerEvent name="SaveAccount" type="c:SaveAccountEvent"/>.

Add this as well : <aura:handler name="SaveAccount" event="c:SaveAccountEvent" action="{!c.saveAccount}"/>.

Create saveAccount method in controller of the component. Pass account to it and call helper method from this function. The method in helper will call saveAccountDetails.

method in controller.js :

saveAccount:function(component,event,helper){
  var acc = component.get("v.account");
  helper.saveAccountToDatabase(component,acc);
}

Method in Helper.js :

saveAccountToDatabase:function(component,account){
   var action = component.get("c.saveAccountDetails");
   action.setParams({account,account});
   action.setCallback(this, function(response) {});
   $A.enqueueAction(action);
}

You must log in to answer this question.

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