简体   繁体   中英

Using JavaScript only, how can I query a google sheet and assign the value of a single cell as a JavaScript variable?

I am wanting to drive a web page using data from a few google sheets.

I've figure out how to query my sheet, but the data displays as a datatable and that's not what I'm looking for. I'd like to be able to take the query cell value and insert it into HTML code. I will also use the value in another query in order to retrieve other information from a different google sheet.

I have two live pages: http://www.bandstand.ca/widget

This page is a starter skeleton version of my project. I have “Day 5” statically coded and formatted for now but want to replace it with query data as per: http://www.bandstand.ca/widget/sas.html

I had tried using getValue(0,0) but must not have had something set right. I am totally new to using queries and have not been able to figure out if JavaScript can do anything with the content of the response. I tried hiding the div element that the query fills and just parsing content of the data table, but again, couldn't figure out a workable solution. I've tried searching through the api documentation but I'm not finding anything that looks right either. Surely there's a way to extract the data and use it within other html. I don't particularly care if the code is clean (as I'm sure you can tell, I've hacked apart other peoples' code to get the sas.html file down to where it's at.) I just want something that works.

I'm a teacher and thought this would be an easy little project to build an in-class announcement page that I could have displayed all the time in my room and have it cycle through my schedule of classes via my easily updated google sheets. So far, not so easy! If anyone can help tweak my code to get what I'm asking, I'd sure be grateful!

You can try something like this:

 function GetCurrentDate() { var currentTime = new Date(); var month = currentTime.getMonth() + 2; var day = currentTime.getDate(); var year = currentTime.getFullYear(); var currentDate = "'" + year + "-" + month + "-" + day + "'"; return currentDate; } function CreateUrl(key, gql) { var gq = 'SELECT '+ gql; var encodedgg = encodeURIComponent(gq); var url = 'https://docs.google.com/spreadsheets/d/' + key + '/gviz/tq?tq=' + encodedgg; return url; } function Request(url, responseFunction) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = this.responseText.substring(this.responseText.IndexOf("(")+1, this.responseText.lastIndexOf(")")); var responseJSON = JSON.parse(response); responseFunction(responseJSON); } }; xmlhttp.open("GET", url, true); xmlhttp.send(); } function preview(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; elm.innerHTML = value; }) } var gsKey = '1-dNm_AKv3Iiy-ggLjGJKHPwUqs379QJh0e4SzbEPcJQ'; var currentDate = GetCurrentDate(); var gql = "C WHERE A = DATE " + currentDate; var url = CreateUrl(gsKey, gql); var previewElement = document.getElementById('preview'); preview(previewElement, url); 
 <html> <head> <title>Student Announcement System</title> </head> <body> <div id="preview">initial value</div> </body> </html> 

Here is link to jsbin snippet . (Inline stackoverflow snippet might not work because of CORS and Access-Control-Allow-Origin .)

EDIT after Greg Duguid's comment :

There are three problems with your code:

  1. Your scripts are not working at all. Try to run following snippet:

 <script> document.write("Text 1") </script> <script language = "text/javascript"> document.write("Text 2") </script> <script type = "text/javascript"> document.write("Text 3") </script> 

When you run it you should get something like Text 1 Text 3 and that is because <script language = "text/javascript"> is wrong and won't work, language parameter is deprecated and you should use type instead. Also in HTML5 you can omit type parameter so it is best to use syntax like this <script>document.write("Text")</script> .

  1. There is syntax error in function preview : last bracket ( should be ) .

 // OLD CODE /* function preview(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; //elm.innerHTML = value; DayNumber = value; } ( // ERROR IS IN THIS LINE } */ // NEW CODE function preview(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; //elm.innerHTML = value; DayNumber = value; } ) // error WAS in this line } 

  1. Code in line:

      <font size="+6" color="#FFFF00">Day <script>document.write(DayNumber);</script></font> 

    When you call function document.write(DayNumber) variable DayNumber is equal to "" because function preview is still not executed at that moment. Reason for this is that execution of function preview takes time. (Because you are retrieving data from sheet document, usually when you retrieve data from server or something similar that takes time.) Execution of code in javascript is asynchronous which means that javscript doesn't wait for function to finish with execution and goes on. Look at this example:

     function getData() { // some function that takes time to get data from server, ducument, or something else return data; } var data = getData(); document.write(data); 

    In first line function getData() is called, but data will be set to undefined because program will not wait for function getData() to return its value. So function document.write(data) will not preview anything.

    (Also it is not good practice to use script tag inside another tag. So you should avoid putting script tag inside font tag like this: <font size="+6" color="#FFFF00">Day <script>document.write(DayNumber);</script></font> .)

    Solution for this problem is that you add id to you font tag and than change text in font tag in javascript inside function preview :

 function GetCurrentDate() { var currentTime = new Date(); var month = currentTime.getMonth(); var day = currentTime.getDate() + 1; var year = currentTime.getFullYear(); var currentDate = "'" + year + "-" + month + "-" + day + "'"; return currentDate; } function CreateUrl(key, gql) { var gq = 'SELECT '+ gql; var encodedgg = encodeURIComponent(gq); var url = 'https://docs.google.com/spreadsheets/d/' + key + '/gviz/tq?tq=' + encodedgg; return url; } function Request(url, responseFunction) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = this.responseText.substring(this.responseText.IndexOf("(")+1, this.responseText.lastIndexOf(")")); var responseJSON = JSON.parse(response); responseFunction(responseJSON); } }; xmlhttp.open("GET", url, true); xmlhttp.send(); } function preview(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; elm.innerHTML += " " + value; } ) } var gsKey = '1-dNm_AKv3Iiy-ggLjGJKHPwUqs379QJh0e4SzbEPcJQ'; var currentDate = GetCurrentDate(); var gql = "C WHERE A = DATE " + currentDate; var url = CreateUrl(gsKey, gql); var previewElement = document.getElementById('preview'); preview(previewElement, url); 
 <html> <title>Student Announcement System</title> <body> <font size="+6" color="#FFFF00" id="preview">Day</font> </body> </html> 

This last code should be solution to your problem. Also here is link to jsbin snippet (because stackoverflow snippet might not work when you run it).

EDIT after second Greg Duguid's comment :

Sorry it took little longer to answer. Problem is in line:

var previewElement = document.getElementById('preview');

When this line is executed previewElement is not found and it is set to undefined . This is because javascript code in script tag ( <script>...</script> ) is before body tag ( <body>...</body> ) so code is executed before elements in body are defined. So when your page is run, first javascript code is executed and then element <font id="preview">Day</font> is defined. There is simple solution for this: You need to put your script tag at the end of body like this:

 <html> <head> <style type="text/css"> <!-- body { background-color: #003c66; } --> </style> <title>Student Announcement System</title> </head> <body> <font size="+6" color="#FFFF00" id="preview">Day</font> <script> function GetCurrentDate() { var currentTime = new Date(); var month = currentTime.getMonth()+1; var day = currentTime.getDate(); var year = currentTime.getFullYear(); var currentDate = "'" + year + "-" + month + "-" + day + "'"; return currentDate; } function CreateUrl(key, gql, sheet) { var gq = 'SELECT '+ gql; var encodedgg = encodeURIComponent(gq); var url = 'https://docs.google.com/spreadsheets/d/' + key + '/gviz/tq?tq=' + encodedgg + '&gid=' + sheet; return url; } function Request(url, responseFunction) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = this.responseText.substring(this.responseText.IndexOf("(")+1, this.responseText.lastIndexOf(")")); var responseJSON = JSON.parse(response); responseFunction(responseJSON); } }; xmlhttp.open("GET", url, true); xmlhttp.send(); } function preview(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; elm.innerHTML += " " + value; } ) } var gsKey = '1-dNm_AKv3Iiy-ggLjGJKHPwUqs379QJh0e4SzbEPcJQ'; var gsSheet='349215948'; var currentDate = GetCurrentDate(); var gql = "C WHERE A = DATE " + currentDate; var url = CreateUrl(gsKey, gql, gsSheet); var previewElement = document.getElementById('preview'); preview(previewElement, url); </script> </body> </html> 

And again here is jsbin snippet which should work.

EDIT after this Greg Duguid's comment :

The problem is in your query:

var PERIODgql = "C WHERE A = " + value + " AND B = " + CurrentPeriod;

CurrentPeriod is string so you need to add single quotes around it like this:

var PERIODgql = "C WHERE A = " + value + " AND B = '" + CurrentPeriod + "'";

When it is created, PERIODgql will be something like:

"C WHERE A = 1 AND B = 'P5'"

These queries are similar to SQL queries (which are used to get data form SQL database), you can read more about this here .

Also i noticed your function FindCurrentPeriod :

function FindCurrentPeriod() {
    var CurrentPeriod;
    var CurrentDate = new Date();

    //////////////////////////////
    //FOR TESTING VARIOUS TIMES
    CurrentDate.setHours(14);
    CurrentDate.setMinutes(0);
    //////////////////////////////


    var CurrentHour = CurrentDate.getHours();
    var CurrentMinute = CurrentDate.getMinutes();
    if (CurrentHour < 8) {
        CurrentPeriod = "Before School";
    }

    if (CurrentHour == 8) {
        if (CurrentMinute < 40) {
            CurrentPeriod = "Before School";
        } else {
            CurrentPeriod = "P1";
        }
    }

    if (CurrentHour == 9) {
        if (CurrentMinute < 40) {
            CurrentPeriod = "P1";
        } else {
            if (CurrentMinute < 45) {
                CurrentPeriod = "B12";
            } else {
                CurrentPeriod = "P2";
            }
        }
    }
    if (CurrentHour == 10) {
        if (CurrentMinute < 37) {
            CurrentPeriod = "P2";
        } else {
            if (CurrentMinute < 47) {
                CurrentPeriod = "B23";
            } else {
                CurrentPeriod = "P3";
            }
        }
    }

    if (CurrentHour == 11) {
        if (CurrentMinute < 39) {
            CurrentPeriod = "P3";
        } else {
            if (CurrentMinute < 44) {
                CurrentPeriod = "B34";
            } else {
                CurrentPeriod = "P4";
            }
        }
    }
    if (CurrentHour == 12) {
        if (CurrentMinute < 36) {
            CurrentPeriod = "P4";
        } else {
            CurrentPeriod = "Lunch";
        }
    }

    if (CurrentHour == 13) {
        if (CurrentMinute < 13) {
            CurrentPeriod = "Lunch";
        } else {
            CurrentPeriod = "P5";
        }
    }

    if (CurrentHour == 14) {
        if (CurrentMinute < 5) {
            CurrentPeriod = "P5";
        } else {
            if (CurrentMinute < 10) {
                CurrentPeriod = "B56";
            } else {
                CurrentPeriod = "P6";
            }
        }
    }

    if (CurrentHour == 15) {
        if (CurrentMinute < 2) {
            CurrentPeriod = "P6";
        } else {
            CurrentPeriod = "After School";
        }
    } else {
        CurrentPeriod = "After School";
    }
    return CurrentPeriod;

}

While this is working, it is not really easy to read and there is some repeating conditions so if need to change your code later, that will be harder to do. So I would suggest using a function to help you compare time (in hours and minutes). You can add just short function like this:

function time(hours, minutes) {
    return hours*60 + minutes;
}

Now you can compare times 10:50 and 11:25 like this:

if (time(10,50) < time(11,25)) {
    //part when you do what you want if condition is ture
}

So you can write your function FindCurrentPeriod like this:

function FindCurrentPeriod() {
    var CurrentPeriod;
    var CurrentDate = new Date();

    //////////////////////////////
    //FOR TESTING VARIOUS TIMES
    CurrentDate.setHours(14);
    CurrentDate.setMinutes(0);
    //////////////////////////////

    var CurrentHour = CurrentDate.getHours();
    var CurrentMinute = CurrentDate.getMinutes();
    var cirrentTime = time(CurrentHour, CurrentMinute);

    if (cirrentTime < time(8, 40)) {
        CurrentPeriod = "Before School";
    }
    else if (cirrentTime < time(9, 40)) {
        CurrentPeriod = "P1";
    }
    else if (cirrentTime < time(9, 45)) {
        CurrentPeriod = "B12";
    }
    else if (cirrentTime < time(10, 37)) {
        CurrentPeriod = "P2";
    }
    else if (cirrentTime < time(10, 47)) {
        CurrentPeriod = "B23";
    }
    else if (cirrentTime < time(11, 39)) {
        CurrentPeriod = "P3";
    }
    else if (cirrentTime < time(11, 44)) {
        CurrentPeriod = "P3";
    }
    else if (cirrentTime < time(12, 36)) {
        CurrentPeriod = "P4";
    }
    else if (cirrentTime < time(13, 13)) {
        CurrentPeriod = "Lunch";
    }
    else if (cirrentTime < time(14, 5)) {
        CurrentPeriod = "P5";
    }
    else if (cirrentTime < time(14, 10)) {
        CurrentPeriod = "B56";
    }
    else if (cirrentTime < time(15, 2)) {
        CurrentPeriod = "P6";
    }
    else {
        CurrentPeriod = "After School";
    }


    return CurrentPeriod;

}

This is shorter and also easier to read and change if needed.

Here is whole code in stackoverflow snippet (again I'll add jsbin snippet below, because inline stackoverflow snippet might not work because of CORS rules):

 function preview2(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; elm.innerHTML = value; }) } function GetCurrentDate() { var currentTime = new Date(); var month = currentTime.getMonth() + 1; var day = currentTime.getDate(); var year = currentTime.getFullYear(); var currentDate = "'" + year + "-" + month + "-" + day + "'"; return currentDate; } function CreateUrl(key, gql, sheet) { var gq = 'SELECT ' + gql; var encodedgg = encodeURIComponent(gq); var url = 'https://docs.google.com/spreadsheets/d/' + key + '/gviz/tq?tq=' + encodedgg + '&gid=' + sheet; return url; } function time(hours, minutes) { return hours*60 + minutes; } function FindCurrentPeriod() { var CurrentPeriod; var CurrentDate = new Date(); ////////////////////////////// //FOR TESTING VARIOUS TIMES CurrentDate.setHours(14); CurrentDate.setMinutes(0); ////////////////////////////// var CurrentHour = CurrentDate.getHours(); var CurrentMinute = CurrentDate.getMinutes(); var cirrentTime = time(CurrentHour, CurrentMinute); if (cirrentTime < time(8, 40)) { CurrentPeriod = "Before School"; } else if (cirrentTime < time(9, 40)) { CurrentPeriod = "P1"; } else if (cirrentTime < time(9, 45)) { CurrentPeriod = "B12"; } else if (cirrentTime < time(10, 37)) { CurrentPeriod = "P2"; } else if (cirrentTime < time(10, 47)) { CurrentPeriod = "B23"; } else if (cirrentTime < time(11, 39)) { CurrentPeriod = "P3"; } else if (cirrentTime < time(11, 44)) { CurrentPeriod = "P3"; } else if (cirrentTime < time(12, 36)) { CurrentPeriod = "P4"; } else if (cirrentTime < time(13, 13)) { CurrentPeriod = "Lunch"; } else if (cirrentTime < time(14, 5)) { CurrentPeriod = "P5"; } else if (cirrentTime < time(14, 10)) { CurrentPeriod = "B56"; } else if (cirrentTime < time(15, 2)) { CurrentPeriod = "P6"; } else { CurrentPeriod = "After School"; } return CurrentPeriod; } function preview1(elm, url) { fetch(url) .then(data => data.text()) .then(function(response) { var responseText = response.substring(response.indexOf("(") + 1, response.lastIndexOf(")")); var response = JSON.parse(responseText); var value = response['table']['rows'][0]['c'][0]['v']; elm.innerHTML += " " + value; var CurrentPeriod = FindCurrentPeriod(); var PERIODgsSheet = '618896702'; var PERIODgql = "C WHERE A = " + value + " AND B = '" + CurrentPeriod + "'"; var PeriodURL = CreateUrl(gsKey, PERIODgql, PERIODgsSheet); var periodElement = document.getElementById('period1'); preview2(periodElement, PeriodURL); }) } var gsKey = '1-dNm_AKv3Iiy-ggLjGJKHPwUqs379QJh0e4SzbEPcJQ'; var DAYgsSheet = '349215948'; var currentDate = GetCurrentDate(); var DAYgql = "C WHERE A = DATE " + currentDate; var DayURL = CreateUrl(gsKey, DAYgql, DAYgsSheet); var previewElement = document.getElementById('preview'); preview1(previewElement, DayURL); 
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="refresh" content="600" /> <title>Student Announcement System</title> <style type="text/css"> <!-- body { background-color: #003c66; } --> </style> <!-- CSS Code --> <style type="text/css" scoped> .GeneratedMarquee { font-family:'Arial Black', sans-serif; font-size:8em; font-weight:bold; line-height:2em; text-align:left; color:#ffff00; background-color:#003c66; padding:40pt; } </style> </head> <body> <table width=100%> <tr> <td width=240px> <iframe scrolling="no" frameborder="no" clocktype="html5" style="overflow:hidden;border:0;margin:0;padding:0;width:240px;height:80px;"src="https://www.clocklink.com/html5embed.php?clock=004&timezone=MST&color=white&size=240&Title=&Message=&Target=&From=2018,1,1,0,0,0&Color=white"></iframe> </td> <td nowrap> <center> <font size="80px" color="#FFFF00" id="preview">DAY </font> </center> </td> <td width=100%> <a class="weatherwidget-io" href="https://forecast7.com/en/53d54n113d49/edmonton/" data-label_1="EDMONTON" data-font="Helvetica" data-icons="Climacons Animated" data-days="7" data-theme="original" data-basecolor="#003c66" ></a> <script> !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src='https://weatherwidget.io/js/widget.min.js';fjs.parentNode.insertBefore(js,fjs);}}(document,'script','weatherwidget-io-js'); </script> </td> </tr> </table> <font color="FFFFFF", size="+6"> <script language=javascript> var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; var today = new Date(); document.write(today.toLocaleDateString("en-US", options)); // Saturday, September 17, 2016 formattedDate = today.toLocaleDateString("en-US", options); </script> </font> <br><font size="80px" color="#FFFF00" id="period1">Class:</font> <script src="sas.js"></script> </body> </html> 

Here is jsbin snippet .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM