Loops and APIs¶
Objectives:¶
- Implement a trigger for geocoding “location” data in Google Sheets
- Be able to use loops and conditional statements in JavaScript
- Understand what an API is
- Add data from a Google Sheet into a website
Start by creating a week5
folder in your lab assignments repo.
Optional: If you finished
lab 4
, you can also copy the contents of yourweek_4
folder and skip the following setup section.¶
Setup¶
Create a new html page called index.html
and add this code:
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24<!DOCTYPE html> <html> <head> <title>Basic Leaflet Map</title> <meta charset="utf-8" /> <link rel="shortcut icon" href="#"> <link rel="stylesheet" href="style/style.css"> <!-- Leaflet's css--> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" /> <!-- Leaflet's JavaScript--> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> </head> <body> <div id="map"></div> <div id="survey"> <!-- this is the iframe for our survey --> <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdqVT10bEbUrULMu6Etwj4ZBXGf-LAxcKohAINFbIdZmHS6OA/viewform?embedded=true" width="640" height="654" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe> </div> <script src="js/init.js"></script> </body> </html>
Create a style
folder and create this style.css
:
style/style.css
Create a
1 2 3 4 5 6 7 8 9 10 11 12 13 14body{ display:grid; grid-template-columns: 1fr 1fr; /* this creates an even two column layout*/ grid-template-areas: "mappanel sidepanel" /* this creates one row with map panel on the left and sidepanel on the right */ } #map{ height:90vh; grid-area: mappanel; } #survey{ grid-area: sidepanel; }
js
folder and create thisinit.js
: js/init.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21const map = L.map('map').setView([34.0709, -118.444], 5); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); let url = "GIVE_ME_A_URL" fetch(url) .then(response => { return response.json(); }) .then(data =>{ console.log(data) }) function addMarker(lat,lng,message){ L.marker([lat,lng]).addTo(map).bindPopup(`<h2>${message}</h2>`) return message } addMarker(37,-122,'home land!')
Revisiting Functions¶
Open up your Google Sheet from last week.
Go to column for Location
and remember what column it is, for me it is C
:
Next, add two columns, one for lat
and another for long
:
Now click on Tools
-> Script Editor
:
When you first launch, you will see a blank myFunction()
get ready to paste over it:
Copy and paste the following code into the entire script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Go back to the Google Scripts and click on triggers: Click on Add Trigger:
Click on Select Event Type:
Change to On Form Submit
so that everytime the the form gets submitted a new record gets latitude/longitude added:
Click Save
:
A pop-up should appear, but if you have a pop-up blocker like on FireFox, then you may have to click on Options
:
Then allow this particular popup to appear.
Select your Google Account to continue:
Click on Advanced
:
Click on Go to Untitled Project (unsafe)
Click on Allow
Click on Save
:
Congratulations, now each time a form gets submitted you will be able to map the locations:
Class Exercise #1 - Test your form!¶
- Add 2-3 locations to your Google Form and see if the new locations work.
- What type of locations do not show up?
Answer
Locations that are blank or that are not recognized by the Google Geocoder.Publishing your survey¶
Now that our data is able to be geocoded, we can bring it into our HTML file through JavaScript. But first we have to publish the spreadsheet:
Go to file:
Click on Publish to web
:
Click on Publish
:
Copy the URL in the address bar:
Go to this website:¶
https://sandbox.idre.ucla.edu/tools/gsJson/
Paste the URL in:
Click the button, Get Spreadsheets
:
Click the button, Get Spreadsheets JSON
:
Copy the results:
In the init.js
file paste the entire result into the URL
variable:
js/init.js
In your console, you should now see the Google Spreadsheet data when some one enters information!
1 2 3 4 5 6 7 8let url = "https://spreadsheets.google.com/feeds/list/1j3a2do9HIS6xvpBsKMjmI4soNaqGdlnIkwYQHktmp1U/oua1awz/public/values?alt=json" fetch(url) .then(response => { return response.json(); }) .then(data =>{ console.log(data) }
Time for-loops, but they look.. foreign…¶
In the function that we copy and pasted you may have seen:
1 2 3 4 5 6 7 8 |
|
for
is a keyword for starting thefor loop
(let i = 0;
is a placeholder variable for counting,i
can be anything, but it has be consistent in thefor loop
.i < cells.length
basically says, “run this loop as long as it is less than the total number of cells.”i++
means keep adding while the loop is able to run{}
and finally the brackets are the code block to execute while the loop runs.
This is the basic example of a for
loop. What a for-loop
means is to go through the items and do something each time
. Loops are one of the most critical tool for programmers for automating tasks.
When the loop ends, we say that the loop is broken out of:
Iterable Items¶
Loops can ONLY occur over iterable items, meaning stuff that you can count or go through, such as numbers, lists, objects, and arrays.
In the technical schematic diagram above, notice that the items is a JavaScript array. When the array hits the last item, the loop stops.
For of¶
The for of loop is much easier to understand than the basic for
loops and works as follows:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
letter
or stuff
and it is quite clear what is being looped over inside the scope brackets.
For Each¶
When dealing with arrays, such as this:
1 |
|
.forEach
method, which is much easier to understand, but acts similar to a forLoop
and requires a function
to run:
1 2 3 4 5 6 |
|
Class Exercise #2 - Test your loop!¶
- Create an array of objects 3 or more items
- Loop through an object with some type of
for
loop - Loop through an array of objects with .forEach
- Utilize the
array
with.forEach
in a function
Bonus Exercise¶
- Use the
create marker
function to add your array to the map - Try to create your own for-loop for counting up to the number 10. Hint from MDN
Answer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Connecting to an API¶
An API can be really thought of as an appliance or application and we are just plugging into it so we can access the data it provides.
Let’s see what this means with our data that we just brought in from the Google Sheets:
js/init.js
Notice that the data we got is kind of messy because of the Google API doesn’t officially support our methods.
1 2 3 4 5 6 7 8 9let url = "https://spreadsheets.google.com/feeds/list/1j3a2do9HIS6xvpBsKMjmI4soNaqGdlnIkwYQHktmp1U/oua1awz/public/values?alt=json" fetch(url) .then(response => { return response.json(); }) .then(data =>{ console.log(data) }
Let’s modify our arrow function so that we take the data and clean it up. First we will add the processData
function:
js/init.js
Now, let’s add the function to clean the data up after our data gets returned:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19function processData(theData){ const formattedData = [] /* this array will eventually be populated with the contents of the spreadsheet's rows */ const rows = theData.feed.entry // this is the weird Google Sheet API format we will be removing // we start a for..of.. loop here for(const row of rows) { const formattedRow = {} for(const key in row) { // time to get rid of the weird gsx$ format... if(key.startsWith("gsx$")) { formattedRow[key.replace("gsx$", "")] = row[key].$t } } // add the clean data formattedData.push(formattedRow) } // lets see what the data looks like when its clean! console.log(formattedData) // we can actually add functions here too }
1 2 3 4 5 6 7 8 9 10 |
|
Our data should look nice and clean now!
Time for the final step..
Turning our data into markers¶
Now that our data is cleaned we can use a .forEach
to loop
through our data and run the addMarker()()
function on them. We will add this in our processData
function.
js/init.js
Open the console and look at our data, we should take note of our field names and the be sure to add them to our markers. Also notice that our markers haven’t showed up yet! That’s because we have to modify the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20function processData(theData){ const formattedData = [] /* this array will eventually be populated with the contents of the spreadsheet's rows */ const rows = theData.feed.entry // this is the weird Google Sheet API format we will be removing // we start a for..of.. loop here for(const row of rows) { const formattedRow = {} for(const key in row) { // time to get rid of the weird gsx$ format... if(key.startsWith("gsx$")) { formattedRow[key.replace("gsx$", "")] = row[key].$t } } // add the clean data formattedData.push(formattedRow) } // lets see what the data looks like when its clean! console.log(formattedData) // we can actually add functions here too formattedData.forEach(addMarker) }
addMarker()
function to use thedata
object:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
js/init.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41const map = L.map('map').setView([34.0709, -118.444], 5); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); function addMarker(data){ // console.log(data) // these are the names of our fields in the google sheets: L.marker([data.latitude,data.longitude]).addTo(map).bindPopup(`<h2>${data.timestamp}</h2>`) return data.timestamp } let url = "https://spreadsheets.google.com/feeds/list/1j3a2do9HIS6xvpBsKMjmI4soNaqGdlnIkwYQHktmp1U/oua1awz/public/values?alt=json" fetch(url) .then(response => { return response.json(); }) .then(data =>{ // console.log(data) formatData(data) } ) function formatData(theData){ const formattedData = [] /* this array will eventually be populated with the contents of the spreadsheet's rows */ const rows = theData.feed.entry for(const row of rows) { const formattedRow = {} for(const key in row) { if(key.startsWith("gsx$")) { formattedRow[key.replace("gsx$", "")] = row[key].$t } } formattedData.push(formattedRow) } console.log(formattedData) formattedData.forEach(addMarker) }
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24<!DOCTYPE html> <html> <head> <title>Basic Leaflet Map</title> <meta charset="utf-8" /> <link rel="shortcut icon" href="#"> <link rel="stylesheet" href="style/style.css"> <!-- Leaflet's css--> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" /> <!-- Leaflet's JavaScript--> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> </head> <body> <div id="map"></div> <div id="survey"> <!-- this is the iframe for our survey --> <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdqVT10bEbUrULMu6Etwj4ZBXGf-LAxcKohAINFbIdZmHS6OA/viewform?embedded=true" width="640" height="654" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe> </div> <script src="js/init.js"></script> </body> </html>
style/style.css
Congratulations on finishing the lab! You only need to add a few data fields in order to finish the lab assignment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14body{ display:grid; grid-template-columns: 1fr 1fr; /* this creates an even two column layout*/ grid-template-areas: "mappanel sidepanel" /* this creates one row with map panel on the left and sidepanel on the right */ } #map{ height:90vh; grid-area: mappanel; } #survey{ grid-area: sidepanel; }
Lab Assignment #4 - Loops and APIs¶
Due 5/6¶
In this week’s lab, we learned how to loop through data and connect to an API. Your task is to create a mini-version of the final group project for the class that intakes data and maps it.
The requirements are:
- Use any type of for-loop within a JavaScript function that adds API data from a Google Spreadsheet form.
- Add a pop-up with at least 2 fields from the Google Form.
- Add data from Google Spreadsheets into your map
Submission¶
- Commit your changes to GitHub
- Find your
index.html
in theWeek_05
folder and copy the URL. It should look something like this: - https://albertkun.github.io/21S-ASIAAM-191A-Assignments/Week_05/index.html
- Paste your link as a comment in the Discussion forum for Lab Assignment #4:
- https://github.com/albertkun/21S-ASIAAM-191A/discussions/137