Know Your Weather - uses Salesforce Lightning and Salesforce Lightning Design System
Glimpse of the Weather app:
This is a lightning app which makes use of lightning components and lightning design system. Special thanks to Piyush Soni for me helping me on this.Following components have been developed for this app:
- LatLng.cmp - This component gets the current location of user who is accessing this app. This component has an associated JS controller - LatLngController.js and a JS helper - LatLngHelper.js
- Weather.cmp - This component reads the latitude and longitude provided by LatLng.cmp and make a webservice call to openweathermap api and displays the weather data. This component has an associated JS controller - WeatherController.js, a JS helper - WeatherHelper.js, an apex controller which makes the webservice callout - WeatherCtrl.apxc and an apex class to parse the webservice response - WeatherResponse.apxc
Lets take a look at the individual components and try to understand what they are doing.
1) latLngEvent.evt
<aura:event type="APPLICATION" access="global">
<!-- Define an attribute of type Decimal to store the latitude -->
<aura:attribute name="lat" type="Decimal"/>
<!-- Define an attribute of type Decimal to store the longitude -->
<aura:attribute name="lng" type="Decimal"/>
</aura:event>
Description: There are two types of event in lightning - application level event and component level event. Here we have defined an application level event with two attributes of Decimal type to store latitude and longitude of user.
2) LatLng.cmp
<aura:component >
<!-- Handles the init event of the page and calls the doInit method present in JS controller -->
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<!-- Declaring that this compenent can fire an event of type c:latLngEvent -->
<aura:registerEvent name="latLngEvent" type="c:latLngEvent"/>
<!-- Including the weather component -->
<c:Weather />
</aura:component>
Description: This component is responsible to get the current position,i.e., latitude and longitude of the user who is accessing this component. Lets talk about the various tags which are used in this component. The aura:handler tag handles the init event for this component. When the component is initialized on the page load, the method specified in the action attribute of this tag is being called. The aura:registerEvent tag declares that this component can fire an event at some point of time and the type of that event is latLngEvent. The last thing in this component is inclusion of another component named Weather. This component would be created later in this tutorial.
3) LatLngController.js
({
doInit : function(component, event, helper) {
helper.getLatLng(component,event,helper);
}
})
Description: This is the JavaScript controller for our lightning component - LatLng.cmp. This is a pretty straight-forward JS controller which contains a single method called doInit which is called on the initialization of component - LatLng.cmp. The doInit method passes on the call to the JavaScript helper and calls a method named getLatLng. Now you might be wondering that how LatLng.cmp knows that LatLngController.js is its associated controller. This is taken care by the auto-wiring feature of the lightning platform and we don't need to do any explicit wiring to connect a component with its JS controller and JS helper.
4) LatLngHelper.js
({
getLatLng : function(component,event,helper) {
var lat,lng;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = position.coords.latitude;
lng = position.coords.longitude;
helper.fireEvent(component, event, lat, lng);
});
}
},
fireEvent : function(component, event, lat, lng){
var latLngEvent = $A.get("e.c:latLngEvent");
latLngEvent.setParams({
"lat": lat,
"lng": lng
});
latLngEvent.fire();
}
})
Description: This is the JavaScript helper for our lightning component - LatLng.cmp. The helper contains two methods. The first method getLatLng is called from the JS controller. This method makes use of geolocation feature of the browser which comes with HTML 5.0. If your browser does not support HTML 5.0, then this app will not work. In the getLatLng method, we first check if geolocation is supported. If it is supported, then we make an async call to get the lat and lng. Once the async call is completed, we fire an event.
1) latLngEvent.evt
<aura:event type="APPLICATION" access="global">
<!-- Define an attribute of type Decimal to store the latitude -->
<aura:attribute name="lat" type="Decimal"/>
<!-- Define an attribute of type Decimal to store the longitude -->
<aura:attribute name="lng" type="Decimal"/>
</aura:event>
Description: There are two types of event in lightning - application level event and component level event. Here we have defined an application level event with two attributes of Decimal type to store latitude and longitude of user.
2) LatLng.cmp
<aura:component >
<!-- Handles the init event of the page and calls the doInit method present in JS controller -->
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<!-- Declaring that this compenent can fire an event of type c:latLngEvent -->
<aura:registerEvent name="latLngEvent" type="c:latLngEvent"/>
<!-- Including the weather component -->
<c:Weather />
</aura:component>
Description: This component is responsible to get the current position,i.e., latitude and longitude of the user who is accessing this component. Lets talk about the various tags which are used in this component. The aura:handler tag handles the init event for this component. When the component is initialized on the page load, the method specified in the action attribute of this tag is being called. The aura:registerEvent tag declares that this component can fire an event at some point of time and the type of that event is latLngEvent. The last thing in this component is inclusion of another component named Weather. This component would be created later in this tutorial.
3) LatLngController.js
({
doInit : function(component, event, helper) {
helper.getLatLng(component,event,helper);
}
})
Description: This is the JavaScript controller for our lightning component - LatLng.cmp. This is a pretty straight-forward JS controller which contains a single method called doInit which is called on the initialization of component - LatLng.cmp. The doInit method passes on the call to the JavaScript helper and calls a method named getLatLng. Now you might be wondering that how LatLng.cmp knows that LatLngController.js is its associated controller. This is taken care by the auto-wiring feature of the lightning platform and we don't need to do any explicit wiring to connect a component with its JS controller and JS helper.
4) LatLngHelper.js
({
getLatLng : function(component,event,helper) {
var lat,lng;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = position.coords.latitude;
lng = position.coords.longitude;
helper.fireEvent(component, event, lat, lng);
});
}
},
fireEvent : function(component, event, lat, lng){
var latLngEvent = $A.get("e.c:latLngEvent");
latLngEvent.setParams({
"lat": lat,
"lng": lng
});
latLngEvent.fire();
}
})
Description: This is the JavaScript helper for our lightning component - LatLng.cmp. The helper contains two methods. The first method getLatLng is called from the JS controller. This method makes use of geolocation feature of the browser which comes with HTML 5.0. If your browser does not support HTML 5.0, then this app will not work. In the getLatLng method, we first check if geolocation is supported. If it is supported, then we make an async call to get the lat and lng. Once the async call is completed, we fire an event.
The event firing part is taken care by another method - fireEvent. The fireEvent method gets the reference of the latLngEvent that we created in Step 1. It then sets the lat and lng params which are defined in the event and then fires the event. Note that the way to get a application level event is different from how you get a component level event.
5) Weather.cmp
<aura:component controller="WeatherCtrl">
<!-- Handles the event of type c:latLngEvent -->
<aura:handler event="c:latLngEvent" action="{!c.getWeatherDetails}"/>
<!-- Define an attribute of type WeatherResponse apex class -->
<aura:attribute name="response" type="WeatherResponse"/>
<!-- Use SLDS classes to style the components -->
<div class="slds-box">
<p><b><div class="slds-text-heading--large">Weather Report - <ui:outputText value="{!v.response.name}"/></div></b></p>
</div><br/>
<ul class="slds-has-dividers--around-space">
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Co-ordinates</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Longitude</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.coord.lon}" format=".00"/></p>
<p class="slds-text-heading--medium">Latitude</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.coord.lat}" format=".00"/></p>
</div>
</div>
</li>
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Temprature</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Avg. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp}" format=".00"/></p>
<p class="slds-text-heading--medium">Max. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp_max}" format=".00"/></p>
<p class="slds-text-heading--medium">Min. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp_min}" format=".00"/></p>
<p class="slds-text-heading--medium">Humidity</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.humidity/100}" format=".00%"/></p>
</div>
</div>
</li>
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Twilight</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Sunrise</p>
<p class="slds-truncate"><ui:outputText value="{!v.response.sys.sunrise}"/></p>
<p class="slds-text-heading--medium">Sunset</p>
<p class="slds-truncate"><ui:outputText value="{!v.response.sys.sunset}"/></p>
</div>
</div>
</li>
</ul>
</aura:component>
Description: Looking at the component, you might think that what is happening here. But believe me, its very simple. Most of the markup is for styling the component using SLDS. Let us look at line by line to understand this component.
5) Weather.cmp
<aura:component controller="WeatherCtrl">
<!-- Handles the event of type c:latLngEvent -->
<aura:handler event="c:latLngEvent" action="{!c.getWeatherDetails}"/>
<!-- Define an attribute of type WeatherResponse apex class -->
<aura:attribute name="response" type="WeatherResponse"/>
<!-- Use SLDS classes to style the components -->
<div class="slds-box">
<p><b><div class="slds-text-heading--large">Weather Report - <ui:outputText value="{!v.response.name}"/></div></b></p>
</div><br/>
<ul class="slds-has-dividers--around-space">
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Co-ordinates</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Longitude</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.coord.lon}" format=".00"/></p>
<p class="slds-text-heading--medium">Latitude</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.coord.lat}" format=".00"/></p>
</div>
</div>
</li>
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Temprature</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Avg. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp}" format=".00"/></p>
<p class="slds-text-heading--medium">Max. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp_max}" format=".00"/></p>
<p class="slds-text-heading--medium">Min. Temprature</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.temp_min}" format=".00"/></p>
<p class="slds-text-heading--medium">Humidity</p>
<p class="slds-truncate"><ui:outputNumber value="{!v.response.main.humidity/100}" format=".00%"/></p>
</div>
</div>
</li>
<li class="slds-item">
<div class="slds-tile slds-tile--board">
<h3 class="slds-truncate" title="Co-ordinates">Twilight</h3>
<div class="slds-tile__detail slds-text-body--small">
<p class="slds-text-heading--medium">Sunrise</p>
<p class="slds-truncate"><ui:outputText value="{!v.response.sys.sunrise}"/></p>
<p class="slds-text-heading--medium">Sunset</p>
<p class="slds-truncate"><ui:outputText value="{!v.response.sys.sunset}"/></p>
</div>
</div>
</li>
</ul>
</aura:component>
Description: Looking at the component, you might think that what is happening here. But believe me, its very simple. Most of the markup is for styling the component using SLDS. Let us look at line by line to understand this component.
The top level tag aura:component has an attribute controller which tells that WeatherCtrl is the apex class which will act as a controller for this component. This class will be used to make all the database calls.
Then we have defined an aura:handler of type latLngEvent that we created in step 1. The LatLng.cmp will fire an event and that event will be handled by Weather.cmp through this tag. On handling this event, it will call the getWeatherDetails method present in its associated JS controller.
After this, we have defined an attribute of type WeatherResponse which is an apex class which we will create later in this tutorial.
The rest of the component just displays the value from this response attribute. Wondering how the response attribute would be populated? This would be populated with the result of our webservice call which we will make through WeatherCtrl.
6) WeatherController.js
({
getWeatherDetails : function(component, event, helper) {
helper.getResponse(component,event);
}
})
Description: This is the JavaScript controller for our lightning component - Weather.cmp which contains a single method called getWeatherDetails.
7) WeatherHelper.js
({
getResponse : function(component,event){
var action = component.get("c.getCalloutResponseContents");
var lat = event.getParam("lat");
var lng = event.getParam("lng");
action.setParams({
"url": 'http://api.openweathermap.org/data/2.5/weather?lat=' +lat+ '&lon=' +lng+ '&appid=9b2719bd93477d05ad2575ccb81cb666&units=metric'
});
action.setCallback(this, function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
component.set("v.response", JSON.parse(response.getReturnValue()));
}
});
$A.enqueueAction(action);
}
})
Description: This is the JavaScript helper for our lightning component - Weather.cmp. The getResponse method calls the getCalloutResponseContents method which is present in our Apex controller which is associated to this lightning component. This is done through component.get method and in the parameter we pass the name of apex method. We store this reference in a variable named action. We now get the parameters from our event - latLngEvent which were set by LatLng.cmp. We use these parameters to form our webservice callout url. We then specify a callback function in which we check whether the response is valid or not. If it is a valid response, then we set the attribute named response which is present in our lightning component - Weather.cmp.
8) WeatherCtrl.apxc
public class WeatherCtrl {
// Pass in the endpoint to be used using the string url
@AuraEnabled
public static String getCalloutResponseContents(String url) {
// 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);
return JSON.serialize(WeatherResponse.parse(res.getBody()));
}
}
Description: This is an apex class which acts as a controller for Weather.cmp. The getCalloutResponseContents method makes a webservice call and then parse the response into WeatherResponse class. The parsed response is then serialized and returned back to the caller.
9) WeatherResponse.apxc
//
// Generated by JSON2Apex http://json2apex.herokuapp.com/
//
public class WeatherResponse{
public static void consumeObject(JSONParser parser) {
Integer depth = 0;
do {
JSONToken curr = parser.getCurrentToken();
if (curr == JSONToken.START_OBJECT ||
curr == JSONToken.START_ARRAY) {
depth++;
} else if (curr == JSONToken.END_OBJECT ||
curr == JSONToken.END_ARRAY) {
depth--;
}
} while (depth > 0 && parser.nextToken() != null);
}
public class Weather {
public Integer id {get;set;}
public String main {get;set;}
public String description {get;set;}
public String icon {get;set;}
public Weather(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'id') {
id = parser.getIntegerValue();
} else if (text == 'main') {
main = parser.getText();
} else if (text == 'description') {
description = parser.getText();
} else if (text == 'icon') {
icon = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'Weather consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Coord {
public Double lon {get;set;}
public Double lat {get;set;}
public Coord(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'lon') {
lon = parser.getDoubleValue();
} else if (text == 'lat') {
lat = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Coord consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Wind {
public Double speed {get;set;}
public Double deg {get;set;}
public Wind(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'speed') {
speed = parser.getDoubleValue();
} else if (text == 'deg') {
deg = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Wind consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Rain {
public Integer h3 {get;set;}
public Rain(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'h3') {
h3 = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Rain consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Clouds {
public Integer all {get;set;}
public Clouds(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'all') {
all = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Clouds consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public Coord coord {get;set;}
public Sys sys {get;set;}
public List<Weather> weather {get;set;}
public Main main {get;set;}
public Wind wind {get;set;}
public Rain rain {get;set;}
public Clouds clouds {get;set;}
public Integer dt {get;set;}
public Integer id {get;set;}
public String name {get;set;}
public Integer cod {get;set;}
public WeatherResponse(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'coord') {
coord = new Coord(parser);
} else if (text == 'sys') {
sys = new Sys(parser);
} else if (text == 'weather') {
weather = new List<Weather>();
while (parser.nextToken() != JSONToken.END_ARRAY) {
weather.add(new Weather(parser));
}
} else if (text == 'main') {
main = new Main(parser);
} else if (text == 'wind') {
wind = new Wind(parser);
} else if (text == 'rain') {
rain = new Rain(parser);
} else if (text == 'clouds') {
clouds = new Clouds(parser);
} else if (text == 'dt') {
dt = parser.getIntegerValue();
} else if (text == 'id') {
id = parser.getIntegerValue();
} else if (text == 'name') {
name = parser.getText();
} else if (text == 'cod') {
cod = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Root consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
public class Sys {
public String country {get;set;}
public String sunrise {get;set;}
public String sunset {get;set;}
public Sys(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'country') {
country = parser.getText();
} else if (text == 'sunrise') {
Integer unixTime = parser.getIntegerValue();
DateTime dateInstance = datetime.newInstanceGmt(1970, 1, 1, 0, 0, 0);
sunrise = dateInstance.addSeconds(unixTime).format();
} else if (text == 'sunset') {
Integer unixTime = parser.getIntegerValue();
DateTime dateInstance = datetime.newInstanceGmt(1970, 1, 1, 0, 0, 0);
sunset = dateInstance.addSeconds(unixTime).format();
} else {
System.debug(LoggingLevel.WARN, 'Sys consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Main {
public Double temp {get;set;}
public Integer humidity {get;set;}
public Integer pressure {get;set;}
public Double temp_min {get;set;}
public Double temp_max {get;set;}
public Main(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'temp') {
temp = parser.getDoubleValue();
} else if (text == 'humidity') {
humidity = parser.getIntegerValue();
} else if (text == 'pressure') {
pressure = parser.getIntegerValue();
} else if (text == 'temp_min') {
temp_min = parser.getDoubleValue();
} else if (text == 'temp_max') {
temp_max = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Main consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public static WeatherResponse parse(String json) {
return new WeatherResponse(System.JSON.createParser(json));
}
}
Description: This class is used to parse the response that we get from the weather webservice. This class can be generated by a Heroku utility app - JSON2Apex http://json2apex.herokuapp.com/. You just need to paste the response of the webservice and this app will create the apex class for you. Some amendments have been made in this class to provide a better user interface.
10) WeatherApp.app
<aura:application access="GLOBAL" extends="force:slds">
<c:LatLng />
</aura:application>
Description: This is our application container which includes the LatLng app. It extends the force:slds application which enables us to use the SLDS in our application. To use SLDS, you do not need to import any static resource now (this used to be a requirement when SLDS) was intrdcuded. But now, just extending force:slds will do the work for you.
Hope you enjoyed reading the article. Any questions or suggestions, please post in comments section.
6) WeatherController.js
({
getWeatherDetails : function(component, event, helper) {
helper.getResponse(component,event);
}
})
Description: This is the JavaScript controller for our lightning component - Weather.cmp which contains a single method called getWeatherDetails.
7) WeatherHelper.js
({
getResponse : function(component,event){
var action = component.get("c.getCalloutResponseContents");
var lat = event.getParam("lat");
var lng = event.getParam("lng");
action.setParams({
"url": 'http://api.openweathermap.org/data/2.5/weather?lat=' +lat+ '&lon=' +lng+ '&appid=9b2719bd93477d05ad2575ccb81cb666&units=metric'
});
action.setCallback(this, function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
component.set("v.response", JSON.parse(response.getReturnValue()));
}
});
$A.enqueueAction(action);
}
})
Description: This is the JavaScript helper for our lightning component - Weather.cmp. The getResponse method calls the getCalloutResponseContents method which is present in our Apex controller which is associated to this lightning component. This is done through component.get method and in the parameter we pass the name of apex method. We store this reference in a variable named action. We now get the parameters from our event - latLngEvent which were set by LatLng.cmp. We use these parameters to form our webservice callout url. We then specify a callback function in which we check whether the response is valid or not. If it is a valid response, then we set the attribute named response which is present in our lightning component - Weather.cmp.
8) WeatherCtrl.apxc
public class WeatherCtrl {
// Pass in the endpoint to be used using the string url
@AuraEnabled
public static String getCalloutResponseContents(String url) {
// 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);
return JSON.serialize(WeatherResponse.parse(res.getBody()));
}
}
Description: This is an apex class which acts as a controller for Weather.cmp. The getCalloutResponseContents method makes a webservice call and then parse the response into WeatherResponse class. The parsed response is then serialized and returned back to the caller.
9) WeatherResponse.apxc
//
// Generated by JSON2Apex http://json2apex.herokuapp.com/
//
public class WeatherResponse{
public static void consumeObject(JSONParser parser) {
Integer depth = 0;
do {
JSONToken curr = parser.getCurrentToken();
if (curr == JSONToken.START_OBJECT ||
curr == JSONToken.START_ARRAY) {
depth++;
} else if (curr == JSONToken.END_OBJECT ||
curr == JSONToken.END_ARRAY) {
depth--;
}
} while (depth > 0 && parser.nextToken() != null);
}
public class Weather {
public Integer id {get;set;}
public String main {get;set;}
public String description {get;set;}
public String icon {get;set;}
public Weather(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'id') {
id = parser.getIntegerValue();
} else if (text == 'main') {
main = parser.getText();
} else if (text == 'description') {
description = parser.getText();
} else if (text == 'icon') {
icon = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'Weather consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Coord {
public Double lon {get;set;}
public Double lat {get;set;}
public Coord(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'lon') {
lon = parser.getDoubleValue();
} else if (text == 'lat') {
lat = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Coord consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Wind {
public Double speed {get;set;}
public Double deg {get;set;}
public Wind(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'speed') {
speed = parser.getDoubleValue();
} else if (text == 'deg') {
deg = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Wind consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Rain {
public Integer h3 {get;set;}
public Rain(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'h3') {
h3 = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Rain consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Clouds {
public Integer all {get;set;}
public Clouds(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'all') {
all = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Clouds consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public Coord coord {get;set;}
public Sys sys {get;set;}
public List<Weather> weather {get;set;}
public Main main {get;set;}
public Wind wind {get;set;}
public Rain rain {get;set;}
public Clouds clouds {get;set;}
public Integer dt {get;set;}
public Integer id {get;set;}
public String name {get;set;}
public Integer cod {get;set;}
public WeatherResponse(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'coord') {
coord = new Coord(parser);
} else if (text == 'sys') {
sys = new Sys(parser);
} else if (text == 'weather') {
weather = new List<Weather>();
while (parser.nextToken() != JSONToken.END_ARRAY) {
weather.add(new Weather(parser));
}
} else if (text == 'main') {
main = new Main(parser);
} else if (text == 'wind') {
wind = new Wind(parser);
} else if (text == 'rain') {
rain = new Rain(parser);
} else if (text == 'clouds') {
clouds = new Clouds(parser);
} else if (text == 'dt') {
dt = parser.getIntegerValue();
} else if (text == 'id') {
id = parser.getIntegerValue();
} else if (text == 'name') {
name = parser.getText();
} else if (text == 'cod') {
cod = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'Root consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
public class Sys {
public String country {get;set;}
public String sunrise {get;set;}
public String sunset {get;set;}
public Sys(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'country') {
country = parser.getText();
} else if (text == 'sunrise') {
Integer unixTime = parser.getIntegerValue();
DateTime dateInstance = datetime.newInstanceGmt(1970, 1, 1, 0, 0, 0);
sunrise = dateInstance.addSeconds(unixTime).format();
} else if (text == 'sunset') {
Integer unixTime = parser.getIntegerValue();
DateTime dateInstance = datetime.newInstanceGmt(1970, 1, 1, 0, 0, 0);
sunset = dateInstance.addSeconds(unixTime).format();
} else {
System.debug(LoggingLevel.WARN, 'Sys consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Main {
public Double temp {get;set;}
public Integer humidity {get;set;}
public Integer pressure {get;set;}
public Double temp_min {get;set;}
public Double temp_max {get;set;}
public Main(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'temp') {
temp = parser.getDoubleValue();
} else if (text == 'humidity') {
humidity = parser.getIntegerValue();
} else if (text == 'pressure') {
pressure = parser.getIntegerValue();
} else if (text == 'temp_min') {
temp_min = parser.getDoubleValue();
} else if (text == 'temp_max') {
temp_max = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'Main consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public static WeatherResponse parse(String json) {
return new WeatherResponse(System.JSON.createParser(json));
}
}
Description: This class is used to parse the response that we get from the weather webservice. This class can be generated by a Heroku utility app - JSON2Apex http://json2apex.herokuapp.com/. You just need to paste the response of the webservice and this app will create the apex class for you. Some amendments have been made in this class to provide a better user interface.
10) WeatherApp.app
<aura:application access="GLOBAL" extends="force:slds">
<c:LatLng />
</aura:application>
Description: This is our application container which includes the LatLng app. It extends the force:slds application which enables us to use the SLDS in our application. To use SLDS, you do not need to import any static resource now (this used to be a requirement when SLDS) was intrdcuded. But now, just extending force:slds will do the work for you.
Hope you enjoyed reading the article. Any questions or suggestions, please post in comments section.
cloudkeeda
ReplyDeletewhat is azure
azure free account
azure data factory
Azure Data Factory Interview Questions
bootaa
bootaa