Javascript and HTML to display temperature and location from Yahoo API - javascript

Question
How can I build a minimal working sample on a site like codepen showing a location and it's temperature using the Yahoo weather API. I need specifically San Diego, CA. And using only HTML and Javascript, not PHP.
Background
I did check the site for a similar question but it only addressed temperature Getting only temperature from Yahoo Weather but it's only answer linked to an overcomplicated tutorial with excessive code.
Other answers on the site only have YML but don't show how to integrate an entire working example.
I was following along to the documentation from Yahoo but there is no working example like how NASA has a live example
Code
I have this CodePen demo
HTML
<div id="output"></div>
Javascript
$(document).ready(function () {
$.getJSON("https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20%3D%202487889&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys/", function (data) {
console.log(data);
console.log(query)
$('#output').append( 'The temperature in' + result.location.["location"] + 'is' + result.condition.["temp"] );
})
})

Here's a working example based on your original code.
Something to note: you were doing this result.location.["location"] Which is invalid. You could use result.location["location"] or result.location.location (neither of which are returned in your result btw)
var queryURL = "https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20%3D%202487889&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys/";
$.getJSON(queryURL, function (data) {
var results = data.query.results
var firstResult = results.channel.item.condition
console.log(firstResult);
var location = 'Unknown' // not returned in response
var temp = firstResult.temp
var text = firstResult.text
$('#output').append('The temperature is ' + temp + '. Forecast calls for '+text);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
Update
Your API query doesn't return location because you have it limited to select item.condition
Change q=select%20item.condition to q=select%20* andd you get a lot more data returned, including location.

Couple of things here:
You are trying to access the location and weather data incorrectly.
You should be using data.location and data.weather since you are
passing the JSON into the function as data in the function (data)
section.
Your API call is not being made properly. Review the documentation here and try to make the call again. https://developer.yahoo.com/weather/
This example does not have any excessive code and would be a great place to start: https://developer.yahoo.com/weather/#get-started

Based on the accepted answer I made one modification to account for the location. It's woeid has to be looked up using something like http://woeid.rosselliot.co.nz/ and then defined as a variable, in my case it was San Diego.
The resulting Javascript was
var queryURL = "https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20%3D%202487889&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys/";
$.getJSON(queryURL, function (data) {
var results = data.query.results
var firstResult = results.channel.item.condition
console.log(firstResult);
var location = 'San Diego'
var temp = firstResult.temp
var text = firstResult.text
$('#output').append('The temperature in ' + location + ' is ' + temp + '. Forecast looks '+ text);
})
full working demo is at http://codepen.io/JGallardo/pen/XpBMRX

Related

Email Sparkline graphs as image/blog/png from Google Sheets range

I tried applying this solution to my case:
Emailing SPARKLINE charts sends blank cells instead of data
But when I try to apply it to my situation an error pops up with:
TypeError: Cannot read property '0' of null
On the executions there is more information about this error:
My GAS code for my Email solution is able to send just the values, and it's here:
function alertDailyInfo() {
let emailAddress = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SANDBOX").getRange("F1").getValue();
let treeIconUrl = "https://d1nhio0ox7pgb.cloudfront.net/_img/g_collection_png/standard/256x256/tree.png";
let treeIconBlob = UrlFetchApp
.fetch(treeIconUrl)
.getBlob()
.setName("treeIconBlob");
let treeUpdate = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SANDBOX").getRange("F6").getValue();
let waterUpdate = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SANDBOX").getRange("F11").getValue();
if (treeUpdate > 0) {
MailApp.sendEmail({
to: emailAddress,
subject: "TREE WATER UPDATE",
htmlBody: "<img src='cid:treeIcon'><br>" + '<br>' + '<br>' +
'<b><u>Tree average is:</u></b>'+ '<br>' + treeUpdate + '<br>' + '<br>' +
'<b><u>Water average is:</u></b>'+ '<br>' + waterUpdate + '<br>' + '<br>'
,
inlineImages:
{
treeIcon: treeIconBlob,
}
});
}
}
The code from the solution presented on the link above and which I have tried to adapt to my situation (please check my file below) is here:
drawTable();
function drawTable() {
let emailAddress1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SANDBOX").getRange("F1").getValue();
var ss_data = getData();
var data = ss_data[0];
var background = ss_data[1];
var fontColor = ss_data[2];
var fontStyles = ss_data[3];
var fontWeight = ss_data[4];
var fontSize = ss_data[5];
var html = "<table border='1'>";
var images = {}; // Added
for (var i = 0; i < data.length; i++) {
html += "<tr>"
for (var j = 0; j < data[i].length; j++) {
if (typeof data[i][j] == "object") { // Added
html += "<td style='height:20px;background:" + background[i][j] + ";color:" + fontColor[i][j] + ";font-style:" + fontStyles[i][j] + ";font-weight:" + fontWeight[i][j] + ";font-size:" + (fontSize[i][j] + 6) + "px;'><img src='cid:img" + i + "'></td>"; // Added
images["img" + i] = data[i][j]; // Added
} else {
html += "<td style='height:20px;background:" + background[i][j] + ";color:" + fontColor[i][j] + ";font-style:" + fontStyles[i][j] + ";font-weight:" + fontWeight[i][j] + ";font-size:" + (fontSize[i][j] + 6) + "px;'>" + data[i][j] + "</td>";
}
}
html += "</tr>";
}
html + "</table>"
MailApp.sendEmail({
to: emailAddress1,
subject: "Spreadsheet Data",
htmlBody: html,
inlineImages: images // Added
})
}
function getData(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SANDBOX");
var ss = sheet.getDataRange();
var val = ss.getDisplayValues();
var background = ss.getBackgrounds();
var fontColor = ss.getFontColors();
var fontStyles = ss.getFontStyles();
var fontWeight = ss.getFontWeights();
var fontSize = ss.getFontSizes();
var formulas = ss.getFormulas(); // Added
val = val.map(function(e, i){return e.map(function(f, j){return f ? f : getSPARKLINE(sheet, formulas[i][j])})}); // Added
return [val,background,fontColor,fontStyles,fontWeight,fontSize];
}
// Added
function getSPARKLINE(sheet, formula) {
formula = formula.toUpperCase();
if (~formula.indexOf("SPARKLINE")) {
var chart = sheet.newChart()
.setChartType(Charts.ChartType.SPARKLINE)
.addRange(sheet.getRange(formula.match(/\w+:\w+/)[0]))
.setTransposeRowsAndColumns(true)
.setOption("showAxisLines", false)
.setOption("showValueLabels", false)
.setOption("width", 200)
.setOption("height", 100)
.setPosition(1, 1, 0, 0)
.build();
sheet.insertChart(chart);
var createdChart = sheet.getCharts()[0];
var blob = createdChart.getAs('image/png');
sheet.removeChart(createdChart);
return blob;
}
}
The code that is working just for the values, which I pasted above (1st block of code), will send me an email like this:
But I need to receive the email like this, with the Sparklines below the values like so:
The code for the Email solution, just for the values, I pasted above (1st block of code) is working. But for some reason when the code from the solution linked above (2nd block of code) is imported/saved into my Google Sheets file GAS script library and adapted to my case, everything stops working, displaying the errors mentioned above.
So basically, as you might have already understood, I need to send emails with the values from Tree Average and Water Average, and I managed to get that working. But I also need for the Sparkline graphs that you can see below, and by checking my file linked below too, to also be sent as images/blobs, just below the info, like in the screenshot above.
Can anyone provide any pointers on what can be missing in applying the solution above or is there a better alternative to sending a SPARKLINE graph as image/blob by email?
Here is my file:
https://docs.google.com/spreadsheets/d/1ExXtmQ8nyuV1o_UtabVJ-TifIbORItFMWjtN6ZlruWc/edit?usp=sharing
EDIT_1:
I made some edits to bring more clarity.
EDIT_2:
As requested this is the formula applied to the first Sparkline, the 2nd one is pretty much the same:
=ARRAYFORMULA( SPARKLINE(QUERY({IFERROR(DATEVALUE(SANDBOX!$A$2:$A)), SANDBOX!$B$2:$B},
"select Col2
where Col2 is not null
and Col1 <= "&INT(MAX(SANDBOX!$A$2:$A))&"
and Col1 > "&INT(MAX(SANDBOX!$A$2:$A))-(
IFERROR(
VLOOKUP(
SUBSTITUTE($F$4," ",""),
{"24HOURS",0;
"2DAYS",1;
"3DAYS",4;
"7DAYS",8;
"2WEEKS",16;
"1MONTH",30;
"3MONTHS",90;
"6MONTHS",180;
"1YEAR",365;
"2YEARS",730;
"3YEARS",1095},
2,FALSE))
)-1, 0),
{"charttype","column";"color","#00bb21";"empty","ignore";"nan","ignore"}))
EDIT_3: At the advice of Rubén I have removed drawTable(); at the beggining of the code block.
I have also transfered the formula for the Sparkline to another helper sheet and link it to the main sheet.
After trying it seems the error does not appear anymore. Although the email received has 2 problems:
I receive the whole sheet in table form, where I just wanted the Sparklines.
Also the Sparklines do not come as images, they do not show up at all. Also where they should appear it says undefined.
I guess the whole sheet is being set because the function getting the range getDataRange(); is getting the whole sheet range.
Here is a screenshot:
As the question you reference explains:
the chart created by SPARKLINE cannot be directly imported to the email.
Why isn't the script working? Because you have not made any significant modifications to it and because you are using a more complex formula than the one proposed in the other question, it is very difficult (if not impossible) to make it work without any modifications.
What are the options? In my opinion you have 3 different options.
Follow the logic of the solution proposed by Tanaike in the other question and using EmbeddedChartBuilder try to shred the content of the FORMULA to achieve the same as with SPARKLINE.
Use the SpreadsheetApp methods to directly get the values from the sheet and build the chart from there.Here is a small example of how you can do it using Chart Service (You could achieve exactly the same with EmbeddedChartBuilder). As you already have a Blob object, you can insert it inside an email as I do inside the Sheet.
function constCreateChart() {
const sS = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('HELPER')
const chart = Charts.newDataTable()
.addColumn(Charts.ColumnType.NUMBER, '')
.addColumn(Charts.ColumnType.NUMBER, '')
// Modfify with your data
// getRange('A2:A15').getValues()...
const builder = [...Array(100).keys()].forEach(n => {
chart.addRow([n, n * n * Math.random()])
})
chart.build()
const chartShap = Charts.newColumnChart()
.setDataTable(chart)
.setLegendPosition(Charts.Position.NONE)
.setOption('hAxis.ticks', [])
.setOption('vAxis.ticks', [])
.build()
sS.insertImage(chartShap.getAs('image/png'), 5, 5)
}
Result
Use this form to request Google to add the possibility to convert charts obtained using SPARKLINES to Blob objects that can be used inside an email.
Documentation
Avalible Options in Chart Service
Fundamentals of Apps Script with Google Sheets #5:Chart and Present Data in Slides
Remove drawTable(); as this line makes that the drawTable function be executed when any function be called.
Apparently the error occurs on .addRange(sheet.getRange(formula.match(/\w+:\w+/)[0])), more specifically because formula.match(/\w+:\w+/) (this expression is intended to extract a range reference of the form A1:B10) returns null. Unfortunately the question doesn't include the formula. One possible solution might be as simple as replacing sheet.getRange(formula.match(/\w+:\w+/)[0]) by another way to set the source range for the temporary chart, but might be a more complex, i.e. adding a helper sheet to be used as the data source for the temporary chart.
NOTE: On Rev 11 one in-cell sparklines chart formula was added. As the formula is pretty complex, the simplest solution is to add a helper sheet to add the QUERY function
QUERY({IFERROR(DATEVALUE(SANDBOX!$A$2:$A)), SANDBOX!$B$2:$B},
"select Col2
where Col2 is not null
and Col1 <= "&INT(MAX(SANDBOX!$A$2:$A))&"
and Col1 > "&INT(MAX(SANDBOX!$A$2:$A))-(
IFERROR(
VLOOKUP(
SUBSTITUTE($F$4," ",""),
{"24HOURS",0;
"2DAYS",1;
"3DAYS",4;
"7DAYS",8;
"2WEEKS",16;
"1MONTH",30;
"3MONTHS",90;
"6MONTHS",180;
"1YEAR",365;
"2YEARS",730;
"3YEARS",1095},
2,FALSE))
)-1, 0)
Then instead of sheet.getRange(formula.match(/\w+:\w+/)[0]) use helperSheet.getDataRange(). You will have to set an appropriate way to declare helperSheet.
Related to Rev. 8
The code on Tanaike's answer reads data from Sheet1 but your sheet is named SANDBOX.

Newbie needs with cryptojs and md5

I am a total newbie in JavaScript. I want to play with a Rest API. This requires the creation of an X-Auth key for authentication.
The documentation said:
The X-Auth-Key header should be constructed using the following
algorithm: md5(api_key + md5(url + X-Auth-User + api_key +
X-Auth-Expires)).
For example, consider a GET request to
https://<server_ip>/api/live_events/1?clean=true by the user 'admin'
with the api_key '1acpJN7oEDn3BDDYhQ' that expires on June 1, 2011
UTC. In this case the url parameter is '/live_events/1' and the
X-Auth-Expires value is '1306886400'. Thus the value of X-Auth-Key
should be computed as follows:
md5('1acpJN7oEDn3BDDYhQ' +
md5('/live_events/1'+'admin'+'1acpJN7oEDn3BDDYhQ'+'1306886400'))
=> md5('1acpJN7oEDn3BDDYhQ' + md5('/live_events/1admin1acpJN7oEDn3BDDYhQ1306886400'))
=> '180c88df8d0d4182385f6eb7e7045a42'
I have tried to implement this with CryptoJs so far, but unfortunately I can't get the values of the example:
<script>
var md5xx = CryptoJS.MD5('/live_events/1admin1acpJN7oEDn3BDDYhQ1306886400')
var md5yy = CryptoJS.MD5(('1acpJN7oEDn3BDDYhQ') + String(md5xx));
console.log(md5yy.toString());
// => 17222238c238b7ac9f76ea8d0fe1e330
</script>
I would really appreciate some help! Thanks in advance!
The md5 hash you obtained 17222238c238b7ac9f76ea8d0fe1e330 is correct.
The given 180c88df8d0d4182385f6eb7e7045a42 example with reverse lookup gives a different link /jobs/1admin1acpJN7oEDn3BDDYhQ1306886400 instead of /live_events/1admin1acpJN7oEDn3BDDYhQ1306886400.
You can cross check with
https://md5.gromweb.com/?md5=180c88df8d0d4182385f6eb7e7045a42
and
https://md5.gromweb.com/?md5=a39ee4e3aa79939249cb6b5e7faead28
//the hash you actually expected
var md5xx = CryptoJS.MD5('/jobs/1admin1acpJN7oEDn3BDDYhQ1306886400')
var md5yy = CryptoJS.MD5(('1acpJN7oEDn3BDDYhQ') + String(md5xx));
console.log(md5yy.toString());
//correct hash according to the given link
var md5xx = CryptoJS.MD5('/live_events/1admin1acpJN7oEDn3BDDYhQ1306886400')
var md5yy = CryptoJS.MD5(('1acpJN7oEDn3BDDYhQ') + String(md5xx));
console.log(md5yy.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

Storing data from a nested firebase object

I am working with an attendance web app which displays information month wise.
Here is my structure of firebase database:Firebase Database Structure
To iterate over the data, i use this:
for(i = 0; i<months.length;i++){
console.log(months[i]);
var datesRef = firebase.database().ref('students/' + currentStudentSap + '/attendance/' + currentSem + '/' + months[i]);
datesRef.on('value',function(snapshot){
var dates = snapshot.val();
var date = Object.keys(dates);
for(j=0;j<date.length;j++){
console.log(date[j]);
var lectureRef = firebase.database().ref('students/' + currentStudentSap + '/attendance/' + currentSem + '/' + months[i] + "/" + date[j]);
lectureRef.on('value',function(snapshot){
var lectures = snapshot.val();
console.log(lectures, typeof(lectures));
});
}
});
}
Here is what I get on the console:
Console Data
What I want to do now is save these stats in some data structure so that I can use them to produce graphical charts.
For eg: "COSTtheory" is a subject and I want to calculate total conducted lectures and total present lectures for each month, and display month wise statistics (such as percentage attended) in HTML.
I don't know exactly how you insert data in Firebase but i would not iterate thru it like you do. Instead i would increment the monthly totals i need to make report each time data is inserted, that way i would be able to show live stats (kind of purpose of a live DB). I would use Firebase database transactions with cloud functions to achieve this. Transactions ensure data consistency.

Variable Returning NaN Value - Cannot find out why

I am having to pickup from where someone in the business left off many years ago with an aging texting system.
It was built using ASP classic and sends a string to an API that then texts out, all this is neither here nor there. The problem i have is no JS experience, I am am a SQL Developer and did a little bit of ASP Classic (VBScript) years ago.
This piece of JScript picks up information from several form boxes and then places them in a string which is then passed to variable on a processing page to text out. The fields 'QValue, Indemnity and Excess' are all numeric. The Cover is text and it is replacing the cover text with 'NaN' now I understand this is for 'Not A Number' well that is exactly what it is, not a number but I want the text string.
Here is the snippet of code in question:
<script type="text/javascript">
function changeMessageText()
{
var messagetxt = document.getElementById('message').value
var QValue = document.getElementById('QValue').value
var Cover = document.getElementById('Cover').value
var Excess = document.getElementById('Excess').value
var Indem = document.getElementById('Indemnity').value
var messagetxt=messagetxt.replace("[QValue]", + QValue)
var messagetxt=messagetxt.replace("[Cover]", + Cover2)
var messagetxt=messagetxt.replace("[Excess]", + Excess)
var messagetxt=messagetxt.replace("[Indem]", + Indem)
document.getElementById('messageText').innerHTML = messagetxt;
}
</script>
Cheers.
When you do string.replace(searchvalue,newvalue), there is no need of + before the newValue
var messagetxt=messagetxt.replace("[QValue]", QValue)
//cover or cover2 whichever appropriate
var messagetxt=messagetxt.replace("[Cover]", Cover)
var messagetxt=messagetxt.replace("[Excess]", Excess)
var messagetxt=messagetxt.replace("[Indem]", Indem)
Is it normal that you use Cover2 in the replace where you read the input value and store it in the Cover variable ?
Those are two different variables and from the code you provided, we can only assume that Cover2 is initialized with NaN (which might not be the case, it can be copy/paste error).
Here is how you do it:
var messagetxt = document.getElementById('message').value;
var QValue = document.getElementById('QValue').value
var Cover = document.getElementById('Cover').value
var messagetxt=messagetxt.replace("[QValue]", QValue)
var messagetxt=messagetxt.replace("[Cover]", Cover)
document.getElementById('messagetxt').innerHTML = messagetxt;
Here is a working example of this: http://jsfiddle.net/F24cr/
Enjoy

How to Format fb.created_time

I am new to javascript and I used the tutorial found here: http://www.prettyklicks.com/blog/making-a-facebook-feed-using-the-graph-api-json-and-jquery/291/ but I am having trouble formatting the date given by facebook. My website is http://moussesalon.com/homePage.htm and my code is as follows:
(function($){
$.fn.fbstatus = function(options) {
set = jQuery.extend({
username: 'Removed for privacy',
token: 'Removed for privacy',
loading_text: null
}, options);
function fbstatus_link(text){
return text.replace(/(href="|<a.*?>)?[A-Za-z]+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+/g, function($0, $1) {
return $1 ? $0 : $0.link($0);
});
}
//Set Url of JSON data from the facebook graph api. make sure callback is set with a '?' to overcome the cross domain problems with JSON
var url = "Removed for privacy";
$(this).each(function(i, widget){
var loading = $('<p class="loading">'+set.loading_text+'</p>');
var theObject = $(this);
if (set.loading_text) $(widget).append(loading);
//Use jQuery getJSON method to fetch the data from the url and then create our unordered list with the relevant data.
$.getJSON(url,function(json){
var html = "<ul>";
//loop through and within data array's retrieve the message variable.
$.each(json.data,function(i,fb){
if (fb.message) {
html += "<li>" + fbstatus_link(fb.message) + "<br>" + fb.created_time + "</li>" + "<br>";
}
});
html += "</ul>";
//A little animation once fetched
theObject.animate({opacity:0}, 500, function(){
theObject.html(html);
});
theObject.animate({opacity:1}, 500);
});
});
};
})(jQuery);
Any help would be greatly appreciated.
According to the main Graph API Documentation under 'Dates' you can ask the API to return results in any date format you want - why not just get Facebook to return the dates in your preferred format?
Excerpt from docs:
All date fields are returned as ISO-8601 formatted strings. You can optionally override the date format by specifying a "date_format"
query parameter. The accepted format strings are identical to those
accepted by the php date function. For example,
https://graph.facebook.com/platform/feed?date_format=U returns the
Platform page's feed, with unixtime-formatted dates.
You could use the javascript function
string.substring(from, to);
This will allow you to specify the start character (0 for the start of the string) to the last character you want (length - 5)
fb.created_time.substring(0,(fb.created_time.length-5));
Here is a simple way to do this...
//graph API call
https://graph.facebook.com/YOURNAME?fields=YOURFIELDSHERE&date_format=F j, Y, g:i a&access_token=ACCESSTOKENHERE"
The results will be the date of the post such as; April 13, 2017, 4:40 pm

Categories