본문 바로가기

스타 블로그

Lightning Component For Communicating Server Side Aura Method

반응형

Aura framework provides a javascript action function to send a request from the lightning component to apex controller and it returns the response back to the client side. Please refer this link to know how the server side action is handled by the client-side controller. In this blog we are explaining the best practices can be followed to do this communication.

Implementation

This implementation requires two components. The server communication is modularized into an abstracted component which is then extended to the second component as needed.

Abstract Component

 

  <aura:component abstract="true" extensible="true" access="global" >
  {!v.body}
  </aura:component>
 
  ({
  runServerMethod : function (component, serverMethodName, successCallBack, failureCallback, params ) {
  var self = this;
  var action = component.get(serverMethodName);
  if (params) {
  action.setParams(params);
  }
  action.setCallback( this, function (response) {
  var state = response.getState();
  if (state === "SUCCESS") {
  successCallBack.call(this,response);
  } else if (state === "INCOMPLETE") {
  // show a toast or create a callback to control this state as well.
  console.log("Failed to connect Salesforce!!");
  }else if (state === "ERROR") {
  var errors = response.getError();
  if (!errors) {
  errors = [{"message" : "Unknown Error Occured"}];
  }
  failureCallback.call(this,errors);
  }
   
  });
  $A.enqueueAction(action);
  }
  })
AbstractBase.cmp is the abstract component being extended to the ChildComponent. Please refer my old post which details how extending works in the lighting component.
  • runServerMethod – helper method defined in the AbstractBaseHelper.js file, to interact with the apex controller method.
  • Method Parameters 
    • component – default parameter in the js controller
    • serverMethodName – the name of the server method in the following format, namespace.method_name, eg: c.callApexControllerMethod
  • successCallBack – the callback executes for a successful server transaction
  • failureCallback – the callback executes for a failed transaction
  • params – parameters to be passed to the apex controller method.

response.getState() – provides the action status of the call happened from the client side to server side. The possible action states are NEW, RUNNING, SUCCESS, ERROR, INCOMPLETE and ABORTED.

Refer the link for more details: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_actions_states.htm

You may have noticed that call method is invoked with two parameters in successCallback and failureCallback. The call is a seeded prototype method of vanilla javascript to invoke the function by passing the parameters. Please refer to the link given in the below reference section for details.

Sub Component

The ChildComponent is extended from the AbstractBase component so the subcomponent will have access to all the helper methods of the parent. The sub-component layout consists of input, checkbox and a button control. In addition to that, a couple of aura attributes are defined to store the values of the HTML controls and server responses.

c.sentMessage is a controller event which is triggered by the ‘send message’ button click which is used for invoking the helper method defined in the childComponent.

 

  <aura:component extends="c:AbstractBase" controller="TestApexController">
  <aura:attribute name="message" type="String" default=""/>
  <aura:attribute name="serverMessage" type="String" default="" description="server message assigns to this"/>
  <aura:attribute name="showError" type="Boolean" default="false" />
  <aura:attribute name="showServerError" type="Boolean" default="false" />
  <ui:inputText label="Message" value="{!v.message}" />
  <lightning:input type="checkbox" label="Show Error" name="showErrorCheck" checked="{!v.showError}"/>
  <lightning:button variant="brand" label="Send Message" onclick="{! c.sendMessage }" />
  <br/><br/><br/>
  <aura:if isTrue="{!v.showServerError}">
  Server Message : {!v.serverMessage}
  <aura:set attribute="else">
  Server Message : {!v.serverMessage}
  </aura:set>
  </aura:if>
  </aura:component>
 
  ({
  sendMessage : function(component, event, helper) {
  helper.sendMessage(component,helper);
  }
  })
 
  ({
  sendMessage : function (component,helper) {
  var message = component.get("v.message");
  var showError = component.get("v.showError");
  var param = {"message":message,"showError":showError};
  helper.runServerMethod(component,"c.callApexControllerMethod",function(response){
  component.set("v.serverMessage",response.getReturnValue());
  }, function(errors) {
  component.set("v.showServerError",true);
  component.set("v.serverMessage",errors[0].message);
  },param);
  console.log(message,showError);
   
  }
  })
 

The sendMessage method defined in the helper part of aura bundle is invoked from the controller part. The helper method calls the runServerMethod which is defined in the parent abstract component.

runServerMethod is invoked with the following parameters.

  • component
  • callApexControllerMethod – static method defined in the apex controller, TestApexController
  • success callback – sets the serverMessage attribute with the response message from the server.
  • failure callback – set the showServerError, serverMessage attributes with the server response.
  • param – Collection of input control values – {message:message,showError:showError};
    • message – the value of the input textbox
    • showError – checked or unchecked status as a boolean

TestApexController

The apex method mush have the following attributes.

  • static and public keywords
  • @AuraEnabled annotation

 

  public class TestApexController {
   
  @AuraEnabled
  public static String callApexControllerMethod ( String message, Boolean showError ) {
  String counterMessage = 'Response from apex controller – ' + 'Your Message : ' + message;
  if (showError) {
  throw new AuraHandledException('Custom Exception from the apex controller');
  }
  return counterMessage;
  }
  }
 

The apex method accepts two parameters and returns a string message. The method throws an aura exception if the ‘showError’ parameter value is true

Testing Application

ChildComponent is invoked from the application markup.

 

  <aura:application >
  <c:ChildComponent />
  </aura:application>
 

Calling a Server-Side Action

Call a server-side controller action from a client-side controller. In the client-side controller, you set a callback, which is called after the server-side action is completed. A server-side action can return any object containing serializable JSON data.

A client-side controller is a JavaScript object in object-literal notation containing a map of name-value pairs.

Let’s say that you want to trigger a server-call from a component. The following component contains a button that’s wired to a client-side controller echo action. SimpleServerSideController contains a method that returns a string passed in from the client-side controller.

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

This client-side controller includes an echo action that executes a serverEcho method on a server-side controller.

 

Tip

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.

 
 
 
({
    "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();
            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 (state === "INCOMPLETE") {
                // do something
            }
            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 storable, abortable, background 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);
    }
})

In the client-side controller, we use the value provider of c to invoke a server-side controller action. We also use the c syntax in markup to invoke a client-side controller action.

The cmp.get("c.serverEcho") call indicates that we’re calling the serverEcho method in the server-side controller. The method name in the server-side controller must match everything after the c. in the client-side call. In this case, that’s serverEcho.

The implementation of the serverEcho Apex method is shown in Apex Server-Side Controller Overview.

Use action.setParams() to set data to be passed to the server-side controller. The following call sets the value of the firstName argument on the server-side controller’s serverEcho method based on the firstName attribute value.

 
 
 
action.setParams({ firstName : cmp.get("v.firstName") });

action.setCallback() sets a callback action that is invoked after the server-side action returns.

 
 
 
action.setCallback(this, function(response) { ... });

The server-side action results are available in the response variable, which is the argument of the callback.

response.getState() gets the state of the action returned from the server.

 

Note

You don’t need a cmp.isValid() check in the callback in a client-side controller when you reference the component associated with the client-side controller. The framework automatically checks that the component is valid.

response.getReturnValue() gets the value returned from the server. In this example, the callback function alerts the user with the value returned from the server.

$A.enqueueAction(action) adds the server-side controller action to the queue of actions to be executed. All actions that are enqueued will run at the end of the event loop. Rather than sending a separate request for each individual action, the framework processes the event chain and batches the actions in the queue into one request. The actions are asynchronous and have callbacks.

 

Tip

If your action isn’t executing, make sure that you’re not executing code outside the framework’s normal rerendering lifecycle. For example, if you use window.setTimeout() in an event handler to execute some logic after a time delay, wrap your code in $A.getCallback(). You don't need to use $A.getCallback() if your code is executed as part of the framework's call stack; for example, your code is handling an event or in the callback for a server-side controller action.

Client Payload Data Limit

Use action.setParams() to set data for an action to be passed to a server-side controller.

The framework batches the actions in the queue into one server request. The request payload includes all of the actions and their data serialized into JSON. The request payload limit is 4 MB.

  • Action States
    Call a server-side controller action from a client-side controller. The action can have different states during processing.

 

Function.prototype.call()

The call() method calls a function with a given this value and arguments provided individually.

call()
call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, ... , argN)
Copy to Clipboard

Parameters

thisArg Optional

The value to use as this when calling func.

Note: In certain cases, thisArg may not be the actual value seen by the method.

If the method is a function in non-strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.

arg1, arg2, ...argN Optional

Arguments for the function.

Return value

The result of calling the function with the specified this value and arguments.

Description

The call() allows for a function/method belonging to one object to be assigned and called for a different object.

call() provides a new value of this to the function/method. With call(), you can write a method once and then inherit it in another object, without having to rewrite the method for the new object.

Note: While the syntax of this function is almost identical to that of apply(), the fundamental difference is that call() accepts an argument list, while apply() accepts a single array of arguments.

Examples

Using call() to chain constructors for an object

You can use call to chain constructors for an object (similar to Java).

In the following example, the constructor for the Product object is defined with two parameters: name and price.

Two other functions, Food and Toy, invoke Product, passing this, name, and price. Product initializes the properties name and price, both specialized functions define the category.

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

function Toy(name, price) {
  Product.call(this, name, price);
  this.category = 'toy';
}

const cheese = new Food('feta', 5);
const fun = new Toy('robot', 40);
Copy to Clipboard

Using call() to invoke an anonymous function

In this example, we create an anonymous function and use call to invoke it on every object in an array.

The main purpose of the anonymous function here is to add a print function to every object, which is able to print the correct index of the object in the array.

Note: Passing the object as this value is not strictly necessary, but is done for explanatory purpose.

const animals = [
  { species: 'Lion', name: 'King' },
  { species: 'Whale', name: 'Fail' }
];

for (let i = 0; i < animals.length; i++) {
  (function(i) {
    this.print = function() {
      console.log('#' + i + ' ' + this.species
                  + ': ' + this.name);
    }
    this.print();
  }).call(animals[i], i);
}
Copy to Clipboard

Using call() to invoke a function and specifying the context for 'this'

In the example below, when we call greet, the value of this will be bound to object obj.

function greet() {
  const reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

const obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // cats typically sleep between 12 and 16 hours
Copy to Clipboard

Using call() to invoke a function and without specifying the first argument

In the example below, we invoke the display function without passing the first argument. If the first argument is not passed, the value of this is bound to the global object.

var sData = 'Wisen';

function display() {
  console.log('sData value is %s ', this.sData);
}

display.call();  // sData value is Wisen
Copy to Clipboard

Note: In strict mode, the value of this will be undefined. See below.

'use strict';

var sData = 'Wisen';

function display() {
  console.log('sData value is %s ', this.sData);
}

display.call(); // Cannot read the property of 'sData' of undefined
Copy to Clipboard

Specifications

Specification

ECMAScript Language Specification
# sec-function.prototype.call

Browser compatibility

desktopmobileserverChromeEdgeFirefoxInternet ExplorerOperaSafariWebView AndroidChrome AndroidFirefox for AndroidOpera AndroidSafari on iOSSamsung InternetDenoNode.jscall

 
 
1
 
Toggle history
12
 
Toggle history
1
 
Toggle history
5.5
 
Toggle history
4
 
Toggle history
1
 
Toggle history
1
 
Toggle history
18
 
Toggle history
4
 
Toggle history
10.1
 
Toggle history
1
 
Toggle history
1.0
 
Toggle history
1.0
 
Toggle history
0.10.0
footnote
Toggle history

Legend

Full supportFull support
See implementation notes.
반응형