LockerService has been a source of frustration for many Lightning component developers. But the fact remains that LockerService is here to stay. It’s an important part of security in when using Lightning components from different sources.
LockerService is not just bad news. Now that it’s mandatory, developers can use many long-awaited features. One of those is making Ajax calls directly from Lightning components. This blog will walk you through a demo of making an AJAX call to Google APIs to get information about a location.
Let’s start by going to Setup → CSP Trusted Sites and adding https://maps.googleapis.com as a trusted site. This will allow a Lightning component to make a call to this domain and get information back.
First I decided to build a utility component that can be called from any component to make an Ajax call and process result. Feel free to use this component for demo or actual use as needed.
<aura:component > <!-- Define method to be called by other components --> <aura:method name="callAjax" action="{!c.callAjax}"> <!-- Method can be, for example, GET or POST --> <aura:attribute name="method" type="String" default="GET" /> <!-- URL to call --> <aura:attribute name="url" type="String" /> <!-- Whether the call should be sync or async --> <aura:attribute name="async" type="Boolean" default="true" /> <!-- Callback method on call complete --> <aura:attribute name="callbackMethod" type="Object" /> </aura:method> </aura:component>
({ callAjax : function(component, event, helper) { //Creaet new request var xmlhttp = new XMLHttpRequest(); //Handle response when complete xmlhttp.onreadystatechange = function(component) { if (xmlhttp.readyState == 4 ) { console.log('xmlhttp: ' + xmlhttp); params.callbackMethod.call(this, xmlhttp); } }; var params = event.getParam('arguments'); if (params) { console.log('params:', params); //Set parameters for the request xmlhttp.open(params.method, params.url, params.async); //Send the request xmlhttp.send(); } } })
<aura:component > <!-- Address to send Google to get more information --> <aura:attribute name="address" type="String" access="global" default="1 Market St, San Francisco, CA 94105, USA" /> <!-- Google API key to send if needed; OPTIONAL --> <aura:attribute name="apikey" type="String" access="global" /> <!-- Message information for ui:message component --> <aura:attribute name="msg" type="String" default=""/> <aura:attribute name="msgSeverity" type="String" /> <aura:attribute name="msgTitle" type="String" /> <!-- Add utils component to use aura:method --> <c:Utils aura:id="utils" /> <div class="slds"> <!-- User input to ask for address and API key if needed --> <lightning:input type="text" label="Address" name="{!v.address}" value="{!v.address}" /> <lightning:input type="text" label="API Key" name="{!v.apikey}" value="{!v.apikey}"/> <!-- Send request to Google on button click --> <lightning:button label="Call Ajax" onclick="{!c.buttonPress}" /> <!-- Display errors or return text on success --> <aura:if isTrue="{! v.msg != '' }"> <ui:message severity="{!msgSeverity}" title="{!v.msgTitle}"> {!v.msg} </ui:message> </aura:if> </div> </aura:component>
({ buttonPress : function(component, event, helper) { //Generate URL for request to Google APIs var url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + component.get('v.address'); //Add API key if provided if(!$A.util.isUndefined(component.get('v.apikey'))){ url += '&key=' + component.get('v.apikey'); } //Make Ajax request helper.makeAjaxRequest(component, url); } })
({ makeAjaxRequest : function(component, url) { var utils = component.find('utils'); //Make Ajax request by calling method from utils component utils.callAjax("POST", url, true, function(xmlhttp){ console.log('xmlhttp:', xmlhttp); //Show response text if successful //Display error message otherwise if (xmlhttp.status == 200) { component.set('v.msg', xmlhttp.responseText); component.set('v.msgSeverity', 'information'); component.set('v.msgTitle', 'Success'); } else if (xmlhttp.status == 400) { component.set('v.msg', 'There was an error 400'); component.set('v.msgSeverity', 'error'); component.set('v.msgTitle', 'Error'); }else { component.set('v.msg', 'Something else other than 200 was returned'); component.set('v.msgSeverity', 'error'); component.set('v.msgTitle', 'Error'); } } ); } })
On success, you should see return response from maps.googleapis.com for provided address.
This is a very welcome change and will solve many issues now that we can make calls directly from Lightning components. I came across it this week and wanted to test and share it here.
Note: Source code used in this blog is available at https://github.com/jrattanpal/Blog-LC-Ajax