My previous post shed some light on JSONP and how it works. In this post I will describe how to create a cool SharePoint 2010 WebPart that shows weather forecasts. The actual forecast data is retrieved from the Yahoo Weather Service using a JSONP call.
The WebPart I have written is a SharePoint 2010 Visual WebPart, all logic is implemented in the ascx-file. The WebPart consists of 4 main parts:
(1) A HTML-table that will show the weather forecast
(2) An image with various symbols (sunny, rain, thunderstorm, etc.) corresponding to the weather codes supplied by the Yahoo Weather Service
(3) Some CSS-code to the style the WebPart
(4) JavaScript which will retrieve the weather forecast data from the Yahoo Weather Service using JSONP-calls
HTML:
We will use a basic HTML-table that will show the weather information, nothing fancy. The actual forecast data is added to this table using jQuery.
<div id="weatherData"> <table> <caption class="weather-location"></caption> <thead> <tr class="weather-date"><td></td></tr> </thead> <tbody> <tr class="weather-icon"><td></td></tr> <tr class="weather-max"><td style="font-style:italic; text-align:left;" >Maximum</td></tr> <tr class="weather-min"><td style="font-style:italic; text-align:left;">Minimum</td></tr> </tbody> </table> </div>
Image:
A single image containing all weather symbols is supplied by Yahoo. Using a technique called CSS image sprites it is easy the extract only a single symbol using the condition code provided by the Yahoo Weather Service
CSS:
Some CSS is used to style the WebPart; all very basic CSS:
<style type="text/css"> #weatherData TD { text-align:center; padding-left:15px; padding-right:15px; } #weatherData CAPTION { font-style:italic; font-weight:bold } .weather-icon DIV { background-image: url(http://l.yimg.com/a/lib/ywc/img/wicons.png); margin-left: auto; margin-right: auto; width:61px; height:34px; } </style>
JavaScript:
Now for the cool part; the forecast data is retrieved from the Yahoo Weather Service using JSONP-calls. The WebPart uses 2 different calls; one to retrieve the nearest weather-station code and a second call to retrieve the actual forecast data for that weather-station:
You can try these calls for yourself:
(1) Retrieve weather-station near Maastricht (the city I live in)
(2) Retrieve 5-day forecast for station NLXX0014 in Celsius
By manipulating the parameters in the URL you can retrieve the weather forecasts for different cities, of display the data in Fahrenheit instead of Celsius.
Calling these service in JavaScript is easy using the jQuery library: $.getJSON
<script type="text/javascript" language="javascript"> $(function () { var city = 'Maastricht' var locationQuery = 'SELECT id FROM xml WHERE url="http://xoap.weather.com/search/search?where=' + city + ' " AND itemPath="search.loc"' var locationUrl = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(locationQuery) + '&format=json'; $.getJSON(locationUrl + '&callback=?', function (data) { var locationId = data.query.results.loc.id; $('#weatherData .weather-location').append('Weather for ' + city + ' (' + locationId + ')'); var weatherUnit = 'c'; //c for Celcius, f for Fahrenheit var weatherQuery = 'SELECT * FROM rss WHERE url="http://xml.weather.yahoo.com/forecastrss/' + locationId + '_' + weatherUnit + '.xml"'; var weatherUrl = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(weatherQuery) + '&format=json'; $.getJSON(weatherUrl + '&callback=?', function (data) { var weatherForecasts = data.query.results.item.forecast; for (var i = 0; i < weatherForecasts.length; i++) { var code = weatherForecasts[i].code; $('#weatherData .weather-date').append('<TD>' + weatherForecasts[i].day + ' ' + weatherForecasts[i].date + '</TD>'); $('#weatherData .weather-icon').append('<TD><DIV title="' + weatherForecasts[i].text + '" /></TD>').find('DIV:last').css('background-position', '-' + (61 * code) + 'px 0px'); $('#weatherData .weather-max').append('<TD>' + weatherForecasts[i].high + ' °C</TD>'); $('#weatherData .weather-min').append('<TD>' + weatherForecasts[i].low + ' °C</TD>'); } }); }); }); </script>
Wrapping it up:
As you can see above; using simple client –side techniques such as JavaScript and JSONP- it is possible to call cross-domain services and create a simple but fancy weather WebPart.
I have combined the complete ascx-code (HTML, CSS and JavaScript) so you copy it into your own weather WebPart. Enjoy!
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WeatherWebPartUserControl.ascx.cs" Inherits="AlainDeKlerk.SP2010.Weather.WeatherWebPart.WeatherWebPartUserControl" %> <style type="text/css"> #weatherData TD { text-align:center; padding-left:15px; padding-right:15px; } #weatherData CAPTION { font-style:italic; font-weight:bold } .weather-icon DIV { background-image: url(http://l.yimg.com/a/lib/ywc/img/wicons.png); margin-left: auto; margin-right: auto; width:61px; height:34px; } </style> <div id="weatherData"> <table> <caption class="weather-location"></caption> <thead> <tr class="weather-date"><td></td></tr> </thead> <tbody> <tr class="weather-icon"><td></td></tr> <tr class="weather-max"><td style="font-style:italic; text-align:left;" >Maximum</td></tr> <tr class="weather-min"><td style="font-style:italic; text-align:left;">Minimum</td></tr> </tbody> </table> </div> <script type="text/javascript" language="javascript"> $(function () { var city = 'Maastricht' var locationQuery = 'SELECT id FROM xml WHERE url="http://xoap.weather.com/search/search?where=' + city + ' " AND itemPath="search.loc"' var locationUrl = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(locationQuery) + '&format=json'; $.getJSON(locationUrl + '&callback=?', function (data) { var locationId = data.query.results.loc.id; $('#weatherData .weather-location').append('Weather for ' + city + ' (' + locationId + ')'); var weatherUnit = 'c'; //c for Celcius, f for Fahrenheit var weatherQuery = 'SELECT * FROM rss WHERE url="http://xml.weather.yahoo.com/forecastrss/' + locationId + '_' + weatherUnit + '.xml"'; var weatherUrl = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(weatherQuery) + '&format=json'; $.getJSON(weatherUrl + '&callback=?', function (data) { var weatherForecasts = data.query.results.item.forecast; for (var i = 0; i < weatherForecasts.length; i++) { var code = weatherForecasts[i].code; $('#weatherData .weather-date').append('<TD>' + weatherForecasts[i].day + ' ' + weatherForecasts[i].date + '</TD>'); $('#weatherData .weather-icon').append('<TD><DIV title="' + weatherForecasts[i].text + '" /></TD>').find('DIV:last').css('background-position', '-' + (61 * code) + 'px 0px'); $('#weatherData .weather-max').append('<TD>' + weatherForecasts[i].high + ' °C</TD>'); $('#weatherData .weather-min').append('<TD>' + weatherForecasts[i].low + ' °C</TD>'); } }); }); }); </script>
Hi there,
I have problems making your script work on a SP2013 environment content editor webpart. I am just putting the html, css and js all together within the same webpart. What am I doing wrong ?
Thx,
HSA