Tuesday, 18 December 2018

Lightning components

Lightning is different from apex, for apex developers it's very tough to get into it.
But salesforce coding is all about reading values from front end to back end and vice versa...

Task 1: Set default value dynamically in Lightning components

Component:
---------
<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable" access="global">
    <aura:attribute name="FirstName" type="String"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
 
    <ui:inputText class="slds-lookup__search-input slds-input leftPaddingClass" value="{!v.FirstName}" placeholder="search.."/>
    <p>{!'Name of Salesforce CEO is ' + v.FirstName}</p>
</aura:component>

JavaScript controller:
---------------------
({
    doInit: function(component,event,helper){
        component.set("v.FirstName", "Mark benioff");
    }
})

Task 2: Develop custom opportunity page using Lightning components, You can replace this component with standard New button.

Apex Class:
----------
public class CreateoppRecord {
    @AuraEnabled
    public static Opportunity createRecord(Opportunity oppobj){
        try{
            if(oppobj != null){
                insert oppobj;
            }
        }catch (Exception ex){
            System.debug('Exception -->'+ex);
        }
        return oppobj;
    } 
}

Component:
---------
<aura:component implements="lightning:actionOverride,flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="CreateoppRecord">
    <ltng:require styles="/resource/bootstrap/css/bootstrap.min.css"
                  scripts="/resource/bootstrap/js/jquery.js,/resource/bootstrap/js/bootstrap.min.js"/>
    <aura:attribute name="oppobj" type="Opportunity" default="{'sobjectType': 'opportunity',
                                                              'Name': '',
                                                              'Amount': '',
                                                              'StageName': 'Prospecting',
                                                              'CloseDate': ''
                                                              }"/>
    <div class="slds-modal slds-fade-in-open">
        <div class="slds-modal__container">
            <div class="slds-modal__header">
                <h2 class="slds-text-heading--medium">New Opportunity</h2>
            </div>
            <div class="slds-modal__content slds-p-around--medium slds-grid slds-wrap ">
                <div class="slds-size--1-of-1 slds-p-horizontal_x-small">
                    <label>Opportunity Name</label>
                    <ui:inputText class="form-control" value="{!v.oppobj.Name}"/>
                </div>
                <div class="slds-size--1-of-1 slds-p-horizontal_x-small">
                    <label>Amount</label>
                    <ui:inputText class="form-control" value="{!v.oppobj.Amount}"/>
                </div>
                <div class="slds-size--1-of-1 slds-p-horizontal_x-small">
                    <ui:inputDate aura:id="closedate" label="Close Date" class="field" value="{!v.oppobj.CloseDate}" displayDatePicker="true"/>
                </div>
                <div class="slds-size--1-of-1 slds-p-horizontal_x-small">
                    <ui:inputSelect aura:Id="stagename" multiple="false" label="Stage" class="slds-size--1-of-1 slds-p-horizontal_x-small">
                        <ui:inputSelectOption label="Prospecting" text="Prospecting" value="true"/>
                        <ui:inputSelectOption label="Qualification" text="Qualification"/>
                        <ui:inputSelectOption label="Closed Won" text="Closed Won"/>
                        <ui:inputSelectOption label="Value Proposition" text="Value Proposition"/>
                        <ui:inputSelectOption label="Needs Analysis" text="Needs Analysis"/>
                    </ui:inputSelect> <br/>
                </div>
            </div>
         
            <div class="slds-modal__footer">             
                <lightning:button variant="neutral" label="Cancel" onclick="{!c.cancel}"/>
                <lightning:button variant="brand" label="Submit" onclick="{!c.saverecord}" />
            </div>
        </div>
    </div>
</aura:component>

JavaScript controller:
---------------------
({
    saverecord : function(component, event, helper) {
        var Opportunity = component.get("v.oppobj");
        if($A.util.isEmpty(Opportunity.Name) || $A.util.isUndefined(Opportunity.Name)){
            alert('Opportunity Name is Required');
            return;
        }
        var stagenm = component.find("stagename");
        if($A.util.isEmpty(stagenm) || $A.util.isUndefined(stagenm)){
            alert('Stage Name is Required');
            return;
        }
        if($A.util.isEmpty(Opportunity.CloseDate) || $A.util.isUndefined(Opportunity.CloseDate)){
            alert('Close Date is Required');
            return;
        }
     
        component.set("v.oppobj.StageName", stagenm.get("v.value"));
        var opprec = component.get("v.oppobj");
     
        var action = component.get("c.createRecord");
        action.setParams({"oppobj": opprec});
     
        action.setCallback(this,function(a){
            var state = a.getState();
            if(state == "SUCCESS"){
             
                var oppId = a.getReturnValue().Id;
             
                var newopp = {'sobjectType': 'opportunity',
                              'Name': '',
                              'Amount': '',
                              'StageName': '',
                              'CloseDate': ''
                             };
                component.set("v.oppobj",newopp);
                //  .reload();
                window.location.href =  '/lightning/r/Opportunity/'+oppId+'/view' ;
            } else if(state == "ERROR"){
                alert('Error in calling server side action');
            }
        });
        $A.enqueueAction(action);
    },
 
    cancel : function(component, event, helper) {
        history.go(-1);
    }
})

Wednesday, 9 May 2018

Salesforce: Making API calls from Lightning Components

We can use REST api in Lightning components by using server side controller, because you can't make API calls from client-side code.

Let's take one example to display weather on your Account records, based on address fields on Account records.

we are going to use the Api to get weather from this URL https://openweathermap.org/api.

Just sign up from this URL to get the weather key. https://home.openweathermap.org/users/sign_up

Once you logged in, click on API Keys tab, like shown below.



It will provide one Default Key, save this Key for future use.

Create Remote site setting in your salesforce org. 

Setup | Security Controls | Remote Site Settings | New

Use this URL http://api.openweathermap.org



Now you are all set to write code.

Create a apex class WeatherController.cls in your salesforce org.



public with sharing class WeatherController {

    private static String apiURL = 'http://api.openweathermap.org/data/2.5/';

    private static String apiKey = 'use your API key ';

    private static String pathCurrentWeather = 'weather?appid='+apiKey+'&units=metric&q=';
    
    // Pass in the endpoint to be used using the string url
    private static String getCalloutResponseContents(String url) {
        String result = null;
        // Instantiate a new http object
        Http h = new Http();
        
        // Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('GET');
        
        // Send the request, and return a response
        HttpResponse res = h.send(req);
        if(res.getStatusCode() == 200){
            result = res.getBody();
        }
        return result;
    }

    @AuraEnabled
    public static Object currentWeather(Id recordId) {
        String city;
        if (recordId!=null && recordId.getSobjectType() == Schema.Account.getSObjectType()) {
            Account acc = [Select Id, BillingCity, BillingCountry, BillingLongitude, BillingLatitude from Account WHERE Id=:recordId];
            if (acc!=null) {
                city= acc.BillingCity+' ,'+acc.BillingCountry;
            }
        }
        else if (recordId.getSobjectType() == Schema.Contact.getSObjectType()) {
            Contact con = [Select Id, MailingCity, Mailingcountry from Contact WHERE Id=:recordId];
            if (con!=null) {
                city= con.MailingCity+' ,'+con.MailingCity;
            }
        }
        String weatherUrl = apiURL + pathCurrentWeather + city;
        System.debug('weatherUrl::' + weatherUrl);

        String result = getCalloutResponseContents(weatherUrl);
        System.debug('result::' + result);

        return (result == null)?null:getCalloutResponseContents(weatherUrl);
    }
}


Create Lightning Component:


<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId" controller="WeatherController" >
    <aura:attribute name="weather" type="Object" />
    <aura:attribute name="message" type="String" />
    <aura:attribute name="title" type="String" />
    <aura:attribute name="severity" type="String" />
    <aura:attribute name="recordId" type="Id" />
    <aura:handler name="init" value="{!this}" action="{!c.getCurrentWeather}" />
    
    <ltng:require styles="{! $Resource.SLDS203 + '/assets/styles/salesforce-lightning-design-system.min.css'}" />
    <div class="slds-grid slds-wrap slds-grid--pull-padded">
        <div class="slds-col--padded slds-size--1-of-1">
            <ui:message class="slds-hide" title="{!v.title}" severity="{!v.severity}" closable="true" aura:id="message">
                {!v.message}
            </ui:message>
            
        </div>
        <div class="slds-col--padded slds-size--1-of-1">
            <aura:if isTrue="{!v.weather != null}">
                <div class="slds-page-header" role="banner">
                    <div class="slds-grid">
                        <div class="slds-col slds-has-flexi-truncate">
                            <div class="slds-media slds-media--center slds-no-space slds-grow">
                                <div class="slds-media__body">
                                    <p class="slds-text-heading--label">City</p>
                                    <h1 class="slds-page-header__title slds-m-right--small slds-truncate slds-align-middle" title="Record Title">
                                        {!v.weather.name},&nbsp;{!v.weather.sys.country}
                                    </h1>
                                </div>
                            </div>
                        </div>
                    </div>
                    <ul class="slds-grid slds-page-header__detail-row">
                        <li class="slds-page-header__detail-block">
                            <p class="slds-text-heading--label-normal slds-truncate slds-m-bottom--xx-small" title="Current">Current</p>
                            <p class="slds-text-body--regular slds-truncate">{!v.weather.main.temp}&deg;C</p>
                        </li>
                        <li class="slds-page-header__detail-block">
                            <p class="slds-text-heading--label-normal slds-truncate slds-m-bottom--xx-small" title="Minimum">Minimum</p>
                            <p class="slds-text-body--regular slds-truncate">{!v.weather.main.temp_min}&deg;C</p>
                        </li>
                        <li class="slds-page-header__detail-block">
                            <p class="slds-text-heading--label-normal slds-truncate slds-m-bottom--xx-small" title="Minimum">Maximum</p>
                            <p class="slds-text-body--regular slds-truncate">{!v.weather.main.temp_max}&deg;C</p>
                        </li>
                        <li class="slds-page-header__detail-block">
                            <p class="slds-text-heading--label-normal slds-truncate slds-m-bottom--xx-small" title="Longitude">Longitude</p>
                            <p class="slds-text-body--regular slds-truncate">{!v.weather.coord.lon}</p>
                        </li>
                        <li class="slds-page-header__detail-block">
                            <p class="slds-text-heading--label-normal slds-truncate slds-m-bottom--xx-small" title="Latitude">Latitude</p>
                            <p class="slds-text-body--regular slds-truncate">{!v.weather.coord.lat}</p>
                        </li>
                        <li>
                        <img src="{!$Resource.weather}" style="max-width:30%"></img>
                        </li>
                    </ul>
                </div>
                
            </aura:if>
        </div>
    </div>
</aura:component>

Javascript controller:



({

getCurrentWeather : function(component, event, helper) {

//var city = component.find('city').get('v.value');

helper.getCurrentWeather(component, helper,event);
}
})



Helper:



({

getCurrentWeather : function(component, helper, city) {

var action = component.get('c.currentWeather');

//action.setParams({"city": city});
        action.setParams({recordId:component.get("v.recordId")});
action.setCallback(this, function(response) {
var state = response.getState();

if (state === "SUCCESS") {
var result = response.getReturnValue();
console.log(result);
if(result != null){
result = JSON.parse(result);
if(result.cod == 200){
component.set('v.weather', result);
}else{
helper.message(component, 'Error!', 'error', result.message);
}
}else{
helper.message(component, 'Error!', 'error', 'Some error occured while getting weather data');
}
}else if (state === "INCOMPLETE") {
}else if (state === "ERROR") {
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
helper.message(component, 'Error!', 'error', errors[0].message);
}
} else {
helper.message(component, 'Error!', 'error', 'Unknown Error');
}
}
});
$A.enqueueAction(action);
},
message: function(component, title, severity, message){
component.set('v.message', message);
component.set('v.title', title);
component.set('v.severity', severity);
var ele = component.find('message');
$A.util.removeClass(ele, 'slds-hide');
$A.util.addClass(ele, 'slds-show');
}
})


Execution Time:


Open any Account record in Lightning mode --> Edit page --> Like shown below



Drag and drop your weather Lightning component to header section and don't forget to provide valid Billing address in your account record.

Then your work is done! weather displays in your record like this.



Done