I am trying to build a basic tool to display someones congress representative via zipcode.
The API that I am trying to use is offered for free via: https://whoismyrepresentative.com
The link to get the info via zipcode is: https://whoismyrepresentative.com/getall_mems.php?zip=31023
It can also be formatted for json like this: https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json
I have read a ton of articles on how to display this data but the trouble I am having is getting the data to show up at all.
How can I get the data to display on my page.
My first attempt was based off w3schools example. When the button is clicked is should display the result in the empty div but when I replace the URL, it does not display. When you visit the URL directly the data is there.
My JavaScript knowledge is fairly limited so I will go line by line and maybe I am just misunderstanding something.
$(document).ready(function(){
– Gets the document ready for some jquery
$("button").click(function(){
– Sets up click function on <button>
$.getJSON("https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json", function(results){
– I hope this is what gets the data from the API URL
$.each(results, function(i, field){
– I’m not sure what this does but I am thinking this displays the field for ‘results’
$("div").append(field + " ");
– This will display the data in the empty <div>
Full index.php code
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Find Your Representative</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> $(document).ready(function(){ $("button").click(function(){ $.getJSON("https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json", function(results){ $.each(results, function(i, field){ $("div").append(field + " "); }); }); }); }); </script> </head> <body> <button>Get JSON data</button> <div></div> </body> </html>
ATTEMPT II
OK I think I have a better understanding but am still confused about some stuff below is my updated code based on your sample with some notes.
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Find Your Representative</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> // This is your test data $.getJSON = function(url, callbackFunction) { var jsonFetchedOn2017_12_21 = { "results": [{ "name": "Austin Scott", "party": "Republican", "state": "GA", "district": "8", "phone": "202-225-6531", "office": "2417 Rayburn HOB; Washington DC 20515-1008", "link": "https://austinscott.house.gov" }, { "name": "John Isakson", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3643", "office": "131 Russell Senate Office Building Washington DC 20510", "link": "http://www.isakson.senate.gov" }, { "name": "David Perdue", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3521", "office": "383 Russell Senate Office Building Washington DC 20510", "link": "http://www.perdue.senate.gov" }] }; callbackFunction(jsonFetchedOn2017_12_21); } // I modified this with some alternate names and notes, I also commented out the alerts so I can easily refresh with my constant changes. // This is the start of the script function runAfterDocumentLoads() { causeButtonClicksToLoadJSONData(); } // This creates the function that when <button> is clicked it will do all the stuff // I modified this to load on a specific <button> class incase I have multiple buttons. function causeButtonClicksToLoadJSONData() { var button = $("button.zip"); button.click(loadJSONData); } // So I think this created the variable jQuery represented by a $ I'm not sure I understand why we need it though. // The json_url stores our URL // Then we use the jQuery variable to use the jQuery library so we can use getJSON? Could we have used $.getJSON instead? function loadJSONData() { var jQuery = $; var json_url = "https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json"; jQuery.getJSON(json_url, addJsonToPage); } // we set the jQuery variable again here, not sure why we needed it the first time but also why do we need to set it again? // we set representativeList to be the extractRepresentativeFromJsonResults function // We use jQuery variable to get the jQuery library to we can use .each? not sure how this part works but our list and addtopage functions are in it. function addJsonToPage(jsonResults) { var jQuery = $; var representativeList = extractRepresentativeFromJsonResults(jsonResults); jQuery.each(representativeList, addRepresentativeToPage); } // Not sure where jsonObject comes from function extractRepresentativeFromJsonResults(jsonObject) { return jsonObject.results; } // Not sure where aRepresentative comes from // I changed the div to have a class since I will definetly have multiple <div>'s going on. // I modified the whitespace to wrap each name in a div with a class so I can easily style them // I added phone as well // The last part is what will add the rep name to div.rep function addRepresentativeToPage(arrayIndex, aRepresentative) { var divElementCollection = $("div.rep"); var repName = "<div class='name'>" + aRepresentative.name + "</div>"; var repPhone = "<div class='phone'>" + aRepresentative.phone + "</div>"; divElementCollection.append(repName); divElementCollection.append(repPhone); } // This put the whole thing within .ready so that the script will wait for full page load before it starts. $(document).ready(runAfterDocumentLoads); </script> </head> <body> <button class="zip"> Get JSON data </button> <div class="rep"> <!-- Output area --> </div> </body> </html>
ATTEMPT III
Updated with new comments and questions.
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Find Your Representative</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> // This is your test data $.getJSON = function(url, callbackFunction) { var jsonFetchedOn2017_12_21 = { "results": [{ "name": "Austin Scott", "party": "Republican", "state": "GA", "district": "8", "phone": "202-225-6531", "office": "2417 Rayburn HOB; Washington DC 20515-1008", "link": "https://austinscott.house.gov" }, { "name": "John Isakson", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3643", "office": "131 Russell Senate Office Building Washington DC 20510", "link": "http://www.isakson.senate.gov" }, { "name": "David Perdue", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3521", "office": "383 Russell Senate Office Building Washington DC 20510", "link": "http://www.perdue.senate.gov" }] }; callbackFunction(jsonFetchedOn2017_12_21); } // After the document is ready it will run the setupPage function which contains the causeButtonClickstoLoadJSONdata function - This setupPage function kind of feels like a wrapper for the rest of the code, does that make sense? function setupPage() { causeButtonClicksToLoadJSONData(); } // We setup a variable called button and set to be <button class="start_request"></button> - Why do we put the jQuery $ in front of this? // Then we create a .click event on our button variable to run the function clearOutput. // Then we create another .click event on our button variable to run the function loadJSONData. // These 2 events will run asynchronously, in order, one after the other, when our button with the class of start_request is clicked. function causeButtonClicksToLoadJSONData() { var button = $("button.start_request"); button.click(clearOutput); button.click(loadJSONData); } // We create a variable called outputArea and set it to be a div tag with the class of results. // Then we use the method .empty on our outputArea variable to remove everything within our <div class="results"></div>. function clearOutput() { var outputArea = $("div.results"); outputArea.empty(); } // We create a variable called json_url and store our API URL in it. // Then we run the getJSON method to first request the data from our json_url then send the data to our addJsonToPage function? function loadJSONData() { var json_url = "https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json"; $.getJSON(json_url, addJsonToPage); } // This is where I have my confusion so bare with me. // I see there is a jsonResults parameter but I don't know where this came from, is this the data from .getJSON? // We setup a variable for representativeList and store our extractRepresentativeFromJsonResults function. // Then we use the .each method which is our loop to run through the array of data. In the .each menthod we use representativeList as the index where all the data is stored and addRepresentativeToPage as the element where we create a function to select the data that we want from extractRepresentativeFromJsonResults. // I don't fully understand index and element are but that is was I got from reading the jQuery documentation. Index seems to be the list of data, Element seems to be the location where this data will go. function addJsonToPage(jsonResults) { var representativeList = extractRepresentativeFromJsonResults(jsonResults); $.each(representativeList, addRepresentativeToPage); } // We need to return this data to use it and we want to return the .results section (there is probably a more correct word to use then section) of the data. // Why do we start with the parameter as jsonObject and then change to jsoinResults in the addJsonToPage function? // I believe you were explaining this in the video but it was a little bit hard to hear. function extractRepresentativeFromJsonResults(jsonObject) { return jsonObject.results; } // I think I am getting lost with parameters I seem to just not know where they come from. arrayIndex makes sense by its name but I don't know why it goes there and what it is doing, same with aRepresentative. // We set variable for dig tag and results class // We set variable to get .name, and wrap it in div's // We set variable to get .phone, wrap it in div's // We use .append method to add repName to our output div // We use .append method to add repPhone to our output div function addRepresentativeToPage(arrayIndex, aRepresentative) { var divElementCollection = $("div.results"); var repName = "<div class='name'>" + aRepresentative.name + "</div>"; var repPhone = "<div class='phone'>" + aRepresentative.phone + "</div>"; divElementCollection.append(repName); divElementCollection.append(repPhone); } // This will wait for the document to load execute our code // We do this because if the code is executed before the document is loaded nothing will exist so the code will run on nothing // Does this need to be the last item on the page? Seemingly we need to wait for the document to load before we can run any code which makes me feel like this should be first. $(document).ready(setupPage); </script> </head> <body> <button class="start_request"> Get JSON data </button> <div class="results"> <!-- Output area --> </div> </body> </html>
Advertisement
Answer
You are close.
Let me help by explaining first how to interpret the function calls.
$(document)
is a jQuery selector that fetches the active HTMLDocument object.
On that object, we are then calling the method ready
, which waits for the document to finish loading. It is an event listener that waits for the ‘onReady’ event of the document. Once that event is detected, we know that the document and all its components have been fully loaded.
At that time, we execute the anonymous function within the ready
method call. There we find:
$("button").click( function(){...} )
You are correct. The $("button")
code fetches all objects that are loaded into the document having the “button” tag name. In this case, there is only one button. The method click
is then called, which sets the event listener on the button object, and the event listener will be called each time the associated button is clicked.
The function that is called contains the following code:
$.getJSON("https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json", function(results){ ... });
Because of its location, this code is run each time the button is clicked. The $
symbol is a variable name that links to the loaded jQuery library. Within that library, we are calling the getJSON
method, which will fetch JSON from a provided URL (your first argument), and then it will return it asyncronously to any function that you provide. In this case, you have provided an anonymous function:
function( results ){ $.each(results, function(i, field){ $("div").append(field + " "); }); }
The results will be your JSON object. As you expect.
So far, your understanding of the above was close enough to get you by. Your trouble really starts with understanding $.each()
.
Remember that $
is the jQuery library. each()
is a function that is just like a for…each loop.
In this case, the call to $.each( results, function(i,field){...} );
does the following. It iterates over each item in the results object, and it then calls the function once for each item. The first argument in the function (i
) is the index in the results array, and the second argument (field
) is the actual item itself.
For example, lets assume I have the following code:
var exampleData = ["item1","item2","item3"]; $.each( exampleData, function( i, itemName ){ ... } );
Within each call to the function(i, itemName){...}
block, I will see the following:
- On the first call,
i=0
anditemName="item1"
. - On the second call,
i=1
anditemName="item2"
. - On the third call,
i=2
anditemName="item3"
. - There will be no forth call, because the loop is done.
So, $.each( array, function(){} )
will apply the function to each element of the array.
What this means is that the JSON data that you are interested in will be in the field
variable of the function call, so when the function executes:
$("div").append(field+" ");
The code does the following:
- Pass the value “div” to the jQuery locator, which fetches all instances of items that are identified by “div” tags.
- Call the append method on the DIV element.
- Add the
field
value and a whitespace to the end of the element contents.
In order to understand what is happening, I would recommend using fewer anonymous functions and using console.log(...)
and debugger
statements to help inspect the code while it is running. When you can see in the console what is contained within each field
variable, you can better understand the data that is being presented to you, and then you can play with formatting a little more clearly.
To assist you on your journey, I have refactored the code to be more clear by removing anonymous functions:
/** * I am going to override the jQuery.each method for the purpose of this example. This test environment does not allow external calls to * to fetch other data. This is called a test double... just ignore it. */ $.getJSON = function(url, callbackFunction) { var jsonFetchedOn2017_12_21 = { "results": [{ "name": "Austin Scott", "party": "Republican", "state": "GA", "district": "8", "phone": "202-225-6531", "office": "2417 Rayburn HOB; Washington DC 20515-1008", "link": "https://austinscott.house.gov" }, { "name": "John Isakson", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3643", "office": "131 Russell Senate Office Building Washington DC 20510", "link": "http://www.isakson.senate.gov" }, { "name": "David Perdue", "party": "Republican", "state": "GA", "district": "", "phone": "202-224-3521", "office": "383 Russell Senate Office Building Washington DC 20510", "link": "http://www.perdue.senate.gov" }] }; callbackFunction(jsonFetchedOn2017_12_21); } /** * Start paying attention to the code here below.... * This is essentially the same code that you posted in the question, but I have given the anonymous functions names and * given variables names so that you can understand what each object is. **/ function runAfterDocumentLoads() { alert("runAfterDocumentLoads run only after the button and div elements are loaded."); causeButtonClicksToLoadJSONData(); } function causeButtonClicksToLoadJSONData() { alert("After causeButtonClicksToLoadJSONData run, the button click is linked to the function loadJSONData."); var button = $("button"); button.click(loadJSONData); } function loadJSONData() { alert("loadJSONData runs every time the button is clicked."); var jQuery = $; var json_url = "https://whoismyrepresentative.com/getall_mems.php?zip=31023&output=json"; jQuery.getJSON(json_url, addJsonToPage); } function addJsonToPage(jsonResults) { alert("addJsonToPage runs once after jQuery finishes loading each call the requested URL"); var jQuery = $; //note, I have called the url that you provide and learned that it passes back an array in the results value var representativeList = extractRepresentativeFromJsonResults(jsonResults); jQuery.each(representativeList, addRepresentativeToPage); } function extractRepresentativeFromJsonResults(jsonObject) { return jsonObject.results; } function addRepresentativeToPage(arrayIndex, aRepresentative) { alert("addRepresentativeToPage will run once for every item in the representativeList array."); alert("addRepresentativeToPage adds the item to the div element on the page."); var divElementCollection = $("div"); var jsonTextWithWhitespace = aRepresentative.name + ", "; divElementCollection.append(jsonTextWithWhitespace); } $(document).ready(runAfterDocumentLoads); alert("The document has been asked to call runAfterDocumentLoads when it is finished loading.");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <button>Example Button</button> <div> <!--Output area--> </div>
Side note, the method “getJSON” is a shortcut method, and it is not defined in all versions of jQuery. I had trouble getting this specific method to work in my browser, so it is better, always, to use the main method, which in this case is $.ajax().
Note to Other Users
The answer above remains the recommended action. The user Heck Raiser and I have begun exchanging emails to help further his understanding of the above code. He is updating his question to reflect his increased understanding based on the discussions we are having. This does not change the above answer.
One of the problems that Heck Raiser will face is that his browser is blocking the JSON response because of CORS. I have recommended to him that he make the JSON request from his server and that he direct his browser to call the server code instead. This will keep the domain name the same, which will not raise any flags for the browser and will allow the JSON response to be handled without CORS errors.
Heck Raiser has elected to use PHP for the backend implementation of this, but the language used is irrelevant for the technique. What is important is this: to get around CORS errors, you must call a page that exists on the same domain as the page that the jQuery is currently running from.