Dhrumit Thakkar

Search weather lightning component (City Name | Zip Code)

Blog Image

1. Incorporate Data from The Weather Company in Salesforce : Complete this module from SalesForce Trailhead. It won't take more than 30 minutes.

2. Create account at OpencageData API. We will be using this API to get Longitude and Latitude value and will pass it to IBM API to get weather forecast data.

3. Add your OpencageData API to Remote site setting in Salesforce. Setup -> Remote Site Setting.

4. Add your OppenCageData API to CSP. Setup -> CSP - > Click New Trusted Site -> In Trusted Site URL Field add: https://api.opencagedata.com 


Go to Developer Console.

1. Copy below code and replace in IBMWeather_Current.cmp

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId" controller="IBMWeather_Controller">
    <aura:attribute name="weatherObservationData" type="Object"></aura:attribute>
    <aura:attribute name="weatherForecastData" type="Object[]"></aura:attribute>
    <aura:attribute name="weatherLoaded" type="Boolean" default="false"></aura:attribute>
    <aura:attribute name="weatherLoadedWithIcon" type="Boolean" default="false"></aura:attribute>
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="searchText" type="String" default=''></aura:attribute>
    <aura:attribute name="selectedString" type="String[]" default=''></aura:attribute>
    <aura:attribute name="url" type="json" default=''></aura:attribute>
    <aura:handler name="init" value="{!this}" action="{!c.getWeather}" />
    <aura:if isTrue="{!v.weatherLoaded}">
        
        <lightning:card title="SF-IDEA: Search by city Name" iconName="standard:search">
            
            <div class="slds-p-left_medium slds-p-right_medium">
                <div class="slds-grid slds-gutters slds-p-top_medium">
                    <div class="slds-col slds-size_6-of-12">
                        <ui:inputText value="{!v.searchText}"  placeholder="Search" ></ui:inputText></div>
                    <div class="slds-col slds-size_2-of-12">
                        <button class='slds-button slds-button_brand' onclick="{!c.searchMyWeather}" alternativeText="Search">Search Me!</button>
                    </div>
                </div>
                <div class="slds-col slds-size_2-of-3 slds-p-top--large"> 
                    <ol start="1" id="searchResult" value="{!v.selectedString}" onclick="{!c.selectedValue}" class="slds-has-cards slds-has-inline-block-links--space">
                    </ol>
                </div> 
                
                <lightning:tabset >
                    <lightning:tab >
                        <aura:set attribute="label">Today</aura:set>
                        <div class="slds-grid slds-grid--vertical-align-start">
                            <div>
                                <aura:if isTrue="{!v.weatherLoadedWithIcon}">
                                    <img src="{!$Resource.IBMWeatherIcons_v1+'/icon'+v.weatherObservationData.wx_icon+'.png'}" class="slds-grid--vertical-align-center temp-img-observation"></img>
                                </aura:if>
                            </div>
                            <div>
                                <div class="temp-main">{!v.weatherObservationData.temp}° F | {!v.weatherObservationData.wx_phrase}</div>
                                <table width="300px">
                                    <tr><td>Max / Min Temp: </td><td>{!v.weatherForecastData[0].max_temp} / {!v.weatherForecastData[0].min_temp} ° F</td></tr>
                                    <tr><td>Humidity:  </td><td>{!v.weatherObservationData.rh} %</td></tr>
                                </table>
                            </div>
                        </div>
                    </lightning:tab>
                    <lightning:tab >
                        <aura:set attribute="label">Forecast</aura:set>
                        <aura:iteration items="{!v.weatherForecastData}" var="item">
                            <div class="slds-grid">
                                <div>
                                    <img src="{!$Resource.IBMWeatherIcons_v1+'/icon'+item.day.icon_code+'.png'}" class="temp-img-forecast"></img>
                                </div>
                                <div>
                                    <strong>{!item.day.daypart_name}</strong><br/>{!item.narrative}<br/><br/>
                                </div>
                            </div>
                        </aura:iteration>
                    </lightning:tab>
                    
                    
                </lightning:tabset>
            </div>
        </lightning:card>        
        <br/>
    </aura:if>
</aura:component>


2. Copy below code in IBMWeather_CurrentController.js

({
    getWeather : function(component, event, helper) {
        helper.getWeather(component, event);
    },
    searchMyWeather : function(component,event,helper) {
        console.log('Hi I am in controller');
        helper.searchMyWeather(component, event);
    },
    selectedValue : function(component,event,helper) {
        var s =  component.get("v.selectedString");
        var innerText = event.target.innerText;
        if(innerText != 'Wanna check your spelling and try again ?'){
        component.set("v.searchText", innerText);
        var domDisplay = document.getElementById('searchResult');
        while (domDisplay.firstChild) {
            domDisplay.removeChild(domDisplay.firstChild);
        }
        helper.getsearchedCityWeather(component,event, innerText);
    }
        else {
           component.set("v.searchText", '');
        }
    }
})


3. Copy below code in IBMWeather_CurrentHelper.css

({
    getWeather : function(component, event) {
        this.getWeatherObservation(component);
    },
    getWeatherObservation : function(component) {
        var action = component.get("c.getWeatherObservation");
        action.setParams({recordId:component.get("v.recordId")});
        action.setCallback(this, function(resp) {
            var state = resp.getState();
            console.log(state);
            if (state === 'ERROR') {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        alert("Error message: " + errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
            var observationData = JSON.parse(resp.getReturnValue()).observation;
            if (typeof observationData=='undefined') {
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    title: "No location data!",
                    message: "This record has no valid longitude and latitude data.",
                    type: "success"
                });
                toastEvent.fire();
                return;
            }
            component.set("v.weatherLoadedWithIcon", (observationData.wx_icon!=null));
            component.set("v.weatherObservationData", observationData);
            this.getWeatherForecast(component);
        });
        $A.enqueueAction(action);
    },
    getWeatherForecast : function(component) {
        var action = component.get("c.getWeather3DayForecasts");
        action.setParams({recordId:component.get("v.recordId")});
        action.setCallback(this, function(resp) {
            var state = resp.getState();
            console.log(state);
            if (state === 'ERROR') {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        alert("Error message: " + errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
            component.set("v.weatherForecastData", JSON.parse(resp.getReturnValue()).forecasts);
            component.set("v.weatherLoaded", true);
        });
        $A.enqueueAction(action);
    },
    searchMyWeather : function(component) {
        this.searchForLongLat(component);
    },
    searchForLongLat : function(component) {
        var cityName = new Array();
        var a = component.get("v.searchText");
        var action = component.get("c.getWeatherLongLat");
        var domDisplay = document.getElementById('searchResult');
        action.setParams({"searchField":a});
        
        action.setCallback(this, function(resp) {
            var returnValue = (resp.getReturnValue());
            component.set("v.url", returnValue);
            var r = (JSON.parse(resp.getReturnValue()));
            //    console.log('Hi I am r : ' + r);
            while (domDisplay.firstChild) {
                domDisplay.removeChild(domDisplay.firstChild);
            }
            var results = r.results;
            var dis_li, href;
            //   console.log('I am formatted 1:' + r.formatted);
            if(results.length > 0){
                for(var i=0 ; i<results.length ; i++)
                {    
                    
                    // created li element to append each search result   
                    dis_li = document.createElement('li');
                    dis_li.setAttribute('class', 'slds-list__item'); 
                    
                    // created detail section span from JSON data  
                    //   var details_sp = document.createElement('span');
                    //    details_sp.innerText = ' '+details[i] ;
                    //    details_sp.setAttribute('class', 'slds-text-body--small');        
                    
                    // created Title-link from JSON data 
                    href = document.createElement('a');
                    //      href.setAttribute('href', results[i].formatted);
                    href.innerText = results[i].formatted ;        
                    
                    dis_li.appendChild(href);
                    //     dis_li.appendChild(details_sp);
                    // append whole dis_li to domDisplay element
                    domDisplay.appendChild(dis_li);
                    cityName.push(results[i].formatted);
                }
            }
            else {
                dis_li = document.createElement('div');
                dis_li.setAttribute('class', 'slds-text-color_destructive');
                href = document.createElement('p');
                href.innerText = 'Wanna check your spelling and try again ?';
                dis_li.appendChild(href);
                domDisplay.appendChild(dis_li);
            }
            component.set("v.selectedString", cityName);
            
        });
        $A.enqueueAction(action);
    },
    
    getsearchedCityWeather : function (component,event,innerText) {
        alert('inner' + innerText);
        var url = (JSON.parse(component.get("v.url")));
        console.log('json url :' + url);
        var results = url.results;
        var lat, lng;
        for(var i=0 ; i<results.length ; i++){
            if(results[i].formatted === innerText){
                console.log('I am geometry : ' + results[i].geometry);
                lat = (JSON.stringify(results[i].geometry.lat));
                lng = (JSON.stringify(results[i].geometry.lng));
            }
        }
        console.log('lat : ' + lat);
        console.log('lng : ' + lng);
        var action = component.get("c.searchedWeathObser");
        action.setParams({lat:lat,lng:lng});
        action.setCallback(this, function(resp) {
            var state = resp.getState();
            console.log(state);
            if (state === 'ERROR') {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        alert("Error message: " + errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
            var observationData = JSON.parse(resp.getReturnValue()).observation;
            if (typeof observationData=='undefined') {
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                    title: "No location data!",
                    message: "This record has no valid longitude and latitude data.",
                    type: "success"
                });
                toastEvent.fire();
                return;
            }
            component.set("v.weatherLoadedWithIcon", (observationData.wx_icon!=null));
            component.set("v.weatherObservationData", observationData);
            this.getsearchedCityForecast(component,event,lat,lng);
        });
        $A.enqueueAction(action);
    },
    getsearchedCityForecast : function(component,event,lat,lng){
        var action = component.get("c.searchedWeathForecast");
        action.setParams({lat:lat,lng:lng});
        action.setCallback(this, function(resp) {
            var state = resp.getState();
            console.log(state);
            if (state === 'ERROR') {
                var errors = resp.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        alert("Error message: " + errors[0].message);
                    }
                } else {
                    console.log("Unknown error");
                }
            }
            component.set("v.weatherForecastData", JSON.parse(resp.getReturnValue()).forecasts);
            component.set("v.weatherLoaded", true);
        });
        $A.enqueueAction(action);
    }
    
})


4. Copy below code to your IBM_Current.css

.THIS .temp-header {
    font-size:1.2em;
}
.THIS .temp-img-observation {
    margin-right: 20px;
    height: 65px;
    width: 65px;
}
.THIS .temp-img-forecast {
    margin-right: 20px;
    height: 38px;
    width: 38px;
}
.THIS .temp-main {
    font-size:1.7em;
}


5. Copy below code to your IBMWeather_Controller.apxc

public class IBMWeather_Controller {
    private static String getWeatherJson(String url, String jsonKey) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('GET');
        Http http = new Http();
        HTTPResponse res = http.send(req);
        Map<String, String> retData = new Map<String, String>();
        return res.getBody();
    }
    private static Double[] resolveGeolocation(Id recordId) {
        double latitude = 0;
        double longitude = 0;
        if (recordId.getSobjectType() == Schema.Account.getSObjectType()) {
            Account acc = [Select Id, BillingLongitude, BillingLatitude from Account WHERE Id=:recordId];
            if (acc!=null) {
                latitude = acc.BillingLatitude;
                longitude = acc.BillingLongitude;
            }
        } else if (recordId.getSobjectType() == Schema.Contact.getSObjectType()) {
            Contact con = [Select Id, MailingLongitude, MailingLatitude from Contact WHERE Id=:recordId];
            if (con!=null) {
                latitude = con.MailingLatitude;
                longitude = con.MailingLongitude;
            }
        } else if (recordId.getSobjectType() == Schema.Lead.getSObjectType()) {
            Lead lea = [Select Id, Address from Lead WHERE Id=:recordId];
            if (lea!=null) {
                latitude = lea.Address.getLatitude();
                longitude = lea.Address.getLongitude();
            }
        }
        return new Double[]{latitude, longitude};
            }
    
    Private static String getCityLogLat(String searchField){
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        searchField = searchField.replace(' ', '%20');
        System.debug('Hi I am searchField : ' + searchField);
        String searchaddress = 'q=' + searchField + '&key=755ae96958f741e480116e6c523b9339&language=en&pretty=1';
        System.debug('Hi I am searchaddress : ' + searchaddress);
        String searchURL = 'https://api.opencagedata.com/geocode/v1/json?q'+ searchaddress;
        req.setEndpoint(searchURL);
        req.setMethod('GET');
        req.setTimeout(6000);
        HttpResponse res = http.send(req);
        System.debug('Hi I am res : ' + JSON.serialize(res));
        if(res.getStatusCode() == 200)
        {
            System.debug('GoogleScript response : ' + res.getBody());
          	System.debug('GoogleScript another response :' + res.getBodyAsBlob());
        }
        return JSON.serialize(res);
            }
    @AuraEnabled
    public static String getWeatherObservation(Id recordId) {
        Double[] geoLocation = resolveGeoLocation(recordId);
        System.debug('Hi I am something meaningful for ya : ' + resolveGeoLocation(recordId));
        String url = 'callout:IBM_Cloud_Weather/api/weather/v1/geocode/' + geoLocation[0] + '/' + geoLocation[1] + '/observations.json?language=' + UserInfo.getLanguage().replace('_','-');
        return getWeatherJson(url, 'observation');
    }
    @AuraEnabled
    public static String getWeather3DayForecasts(Id recordId) {
        Double[] geoLocation = resolveGeoLocation(recordId);
        String url = 'callout:IBM_Cloud_Weather/api/weather/v1/geocode/' + geoLocation[0] + '/' + geoLocation[1] + '/forecast/daily/3day.json?units=m&language=en-US';
        return getWeatherJson(url, 'forecasts');
    }
    @AuraEnabled
    public static String getWeatherAlerts(String country) {
        String url = 'callout:IBM_Cloud_Weather/api/weather/v1/country/' + country + '/alerts.json?language=en-US';
        return getWeatherJson(url, 'alerts');
    }
  
    @AuraEnabled
    public static String getWeatherLongLat(String searchField){
        system.debug('Hi I am searchText :' +searchField);
        
        Http h = new Http(); 
        
        HttpRequest request = new HttpRequest(); // creating http request for wikipedia API
        request.setMethod('GET');
        
        searchField = searchField.replace(' ', '%20');
        String searchaddress = 'q=' + searchField + '&key=755ae96958f741e480116e6c523b9339&language=en&pretty=1';
        System.debug('Hi I am searchaddress : ' + searchaddress);
        String searchURL = 'https://api.opencagedata.com/geocode/v1/json?'+ searchaddress;
        request.setEndpoint(searchURL); 
        
        System.debug('Hi I am searchURL : ' + searchURL);
        String searchResult;
        HTTPResponse res = h.send(request);
        
        // if status is 200 then get API response in searchResult String and return it to lightning controller. 
        
        if (res.getStatusCode() == 200) {
            system.debug('Hi I am res : ' +res);
            searchResult = res.getBody();  // getting API response in 'searchResult' String
            system.debug('Hi I am your searchResult : '+ searchResult);
             // returng response to lightning controller 
        }
        
        // show status and status code if it's other then 200
        
        else {
            System.debug('The status code returned was not expected: ' +
                         res.getStatusCode() + ' ' + res.getStatus());
        }
        return searchResult; 
    }
    
    @AuraEnabled
    public static String searchedWeathObser(String lat, String lng) {
    
        String url = 'callout:IBM_Cloud_Weather/api/weather/v1/geocode/' + lat + '/' + lng + '/observations.json?language=' + UserInfo.getLanguage().replace('_','-');
        return getWeatherJson(url, 'observation');
    }
    
    @AuraEnabled
    public static String searchedWeathForecast(String lat, String lng) {   
       String url = 'callout:IBM_Cloud_Weather/api/weather/v1/geocode/'  + lat + '/' + lng + '/forecast/daily/3day.json?units=m&language=en-US';
        return getWeatherJson(url, 'forecasts');
    }
    
}

VIDEO

MOST VIEW POST

RECOMMENDED POST

POST COMMENT

Please to continue.