The code below holds the info that is being generated into an HTML table.

Key things to know:

  • < table > creates a TABLE
  • < tr > creates a ROW
  • < th > makes the text a column HEADER
  • < tbody id = “results” > defines an element id, to be used within JavaScript
%%html

<!-- HTML table fragment for page -->
<table>
  <thead>
  <tr>
    <th>Joke</th>
    <th>HaHa</th>
    <th>Boohoo</th>
  </tr>
  </thead>
  <tbody id="result">
    <!-- javascript generated data -->
  </tbody>
</table>

Constant variables are declared here with keyword const

Key things to know:

  • The document object “result” represents table body in the HTML above.
  • If you want to access any element in an HTML page in JavaScript, you always start by accessing the document object. In this case, we are accessing “result” and defining a “resultContainer”
  • In the code, in following cells, document elements are created and organized for each Joke, each is added to the “resultContainer” as a row in the table body.
  • Accessing the api is done using the variables url and options, this is setup to fetch the Jokes from the backend
%%js

// prepare HTML defined "result" container for new output
const resultContainer = document.getElementById("result");

// keys for joke reactions
const HAHA = "haha";
const BOOHOO = "boohoo";

// prepare fetch urls
const url = "https://flask.nighthawkcodingsociety.com/api/jokes";
const like_url = url + "/like/";  // haha reaction
const jeer_url = url + "/jeer/";  // boohoo reaction

// prepare fetch GET options
const options = {
  method: 'GET', // *GET, POST, PUT, DELETE, etc.
  mode: 'cors', // no-cors, *cors, same-origin
  cache: 'default', // *default, no-cache, reload, force-cache, only-if-cached
  credentials: 'omit', // include, *same-origin, omit
  headers: {
    'Content-Type': 'application/json'
    // 'Content-Type': 'application/x-www-form-urlencoded',
  },
};

// prepare fetch PUT options, clones with JS Spread Operator (...)
const put_options = {...options, method: 'PUT'}; // clones and replaces method

The below code uses a function called fetch to gather the data from the backend.

Key things to understand:

  • The “url” “response” is checked in case the site is down and returns an error
  • On successful fetch, the code places each Joke in the HTML table body using a “for” loop and creating document elements from each “row” of the fetched “data”.
  • The creation of each Haha and Boohoo “onclick” “button” is also done in the same loop.
  • Updates to backend are setup to occur with each onclick, each click calls the “reaction” function
// fetch the API
fetch(url, options)
  // response is a RESTful "promise" on any successful fetch
  .then(response => {
    // check for response errors
    if (response.status !== 200) {
        error('GET API response failure: ' + response.status);
        return;
    }
    // valid response will have JSON data
    response.json().then(data => {
        console.log(data);
        for (const row of data) {
          // make "tr element" for each "row of data"
          const tr = document.createElement("tr");
          
          // td for joke cell
          const joke = document.createElement("td");
            joke.innerHTML = row.id + ". " + row.joke;  // add fetched data to innerHTML

          // td for haha cell with onclick actions
          const haha = document.createElement("td");
            const haha_but = document.createElement('button');
            haha_but.id = HAHA+row.id   // establishes a HAHA JS id for cell
            haha_but.innerHTML = row.haha;  // add fetched "haha count" to innerHTML
            haha_but.onclick = function () {
              // onclick function call with "like parameters"
              reaction(HAHA, like_url+row.id, haha_but.id);  
            };
            haha.appendChild(haha_but);  // add "haha button" to haha cell

          // td for boohoo cell with onclick actions
          const boohoo = document.createElement("td");
            const boohoo_but = document.createElement('button');
            boohoo_but.id = BOOHOO+row.id  // establishes a BOOHOO JS id for cell
            boohoo_but.innerHTML = row.boohoo;  // add fetched "boohoo count" to innerHTML
            boohoo_but.onclick = function () {
              // onclick function call with "jeer parameters"
              reaction(BOOHOO, jeer_url+row.id, boohoo_but.id);  
            };
            boohoo.appendChild(boohoo_but);  // add "boohoo button" to boohoo cell
            
          // this builds ALL td's (cells) into tr (row) element
          tr.appendChild(joke);
          tr.appendChild(haha);
          tr.appendChild(boohoo);

          // this adds all the tr (row) work above to the HTML "result" container
          resultContainer.appendChild(tr);
        }
    })
})

// catch fetch errors (ie Nginx ACCESS to server blocked)
.catch(err => {
  error(err + " " + url);
});

The below code uses fetch to update backend data using “put_options”. The purpose is to update Hahaa and Bohoo counters in backend.

Key things to understand:

  • The “url” “response” is checked to verify update occurred
  • The element id of button clicked is updated with the data returned from the API.
  • Note, the elemID is received as parameter. This data was setup when the button was created in former cell.
// Reaction function to likes or jeers user actions
function reaction(type, put_url, elemID) {

  // fetch the API
  fetch(put_url, put_options)
  // response is a RESTful "promise" on any successful fetch
  .then(response => {
    // check for response errors
    if (response.status !== 200) {
        error("PUT API response failure: " + response.status)
        return;  // api failure
    }
    // valid response will have JSON data
    response.json().then(data => {
        console.log(data);
        // Likes or Jeers updated/incremented
        if (type === HAHA) // like data element
          document.getElementById(elemID).innerHTML = data.haha;  // fetched haha data assigned to haha Document Object Model (DOM)
        else if (type === BOOHOO) // jeer data element
          document.getElementById(elemID).innerHTML = data.boohoo;  // fetched boohoo data assigned to boohoo Document Object Model (DOM)
        else
          error("unknown type: " + type);  // should never occur
    })
  })
  // catch fetch errors (ie Nginx ACCESS to server blocked)
  .catch(err => {
    error(err + " " + put_url);
  });
  
}
  
// Something went wrong with actions or responses
function error(err) {
  // log as Error in console
  console.error(err);
  // append error to resultContainer
  const tr = document.createElement("tr");
  const td = document.createElement("td");
  td.innerHTML = err;
  tr.appendChild(td);
  resultContainer.appendChild(tr);
}

Hacks

The code below relates to the rapidapi you worked with last week.

  • What are some similarities you see with the javascript for the jokes api?
  • In a blogpost, break up the code in cells like done above and try to describe what this code is doing.
<!-- HTML table fragment for page -->
<table>
  <thead>
  <tr>
    <th>Time</th>
    <th>All-time Cases</th>
    <th>Recorded Deaths</th>
    <th>Active Cases</th>
  </tr>
  </thead>
  <tbody>
    <td id="time"></td>
    <td id="total_cases"></td>
    <td id="total_deaths"></td>
    <td id="active_cases"></td>
  </tbody>
</table>

<table>
  <thead>
  <tr>
    <th>Country</th>
    <th>All-time Cases</th>
    <th>Recorded Deaths</th>
    <th>Active Cases</th>
  </tr>
  </thead>
  <tbody id="result">
    <!-- generated rows -->
  </tbody>
</table>

<!-- Script is layed out in a sequence (no function) and will execute when page is loaded -->
<script>
  // prepare HTML result container for new output
  const resultContainer = document.getElementById("result");

  // prepare fetch options
  const url = "https://flask.nighthawkcodingsociety.com/api/covid/";
  const headers = {
    method: 'GET', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'default', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'omit', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
  };

  // fetch the API
  fetch(url, headers)
    // response is a RESTful "promise" on any successful fetch
    .then(response => {
      // check for response errors
      if (response.status !== 200) {
          const errorMsg = 'Database response error: ' + response.status;
          console.log(errorMsg);
          const tr = document.createElement("tr");
          const td = document.createElement("td");
          td.innerHTML = errorMsg;
          tr.appendChild(td);
          resultContainer.appendChild(tr);
          return;
      }
      // valid response will have json data
      response.json().then(data => {
          console.log(data);
          console.log(data.world_total)

          // World Data
          document.getElementById("time").innerHTML = data.world_total.statistic_taken_at;
          document.getElementById("total_cases").innerHTML = data.world_total.total_cases;
          document.getElementById("total_deaths").innerHTML = data.world_total.total_deaths;
          document.getElementById("active_cases").innerHTML = data.world_total.active_cases;

          // Country data
          for (const row of data.countries_stat) {
            console.log(row);

            // tr for each row
            const tr = document.createElement("tr");
            // td for each column
            const name = document.createElement("td");
            const cases = document.createElement("td");
            const deaths = document.createElement("td");
            const active = document.createElement("td");

            // data is specific to the API
            name.innerHTML = row.country_name;
            cases.innerHTML = row.cases; 
            deaths.innerHTML = row.deaths; 
            active.innerHTML = row.active_cases; 

            // this builds td's into tr
            tr.appendChild(name);
            tr.appendChild(cases);
            tr.appendChild(deaths);
            tr.appendChild(active);

            // add HTML to container
            resultContainer.appendChild(tr);
          }
      })
  })
  // catch fetch errors (ie ACCESS to server blocked)
  .catch(err => {
    console.error(err);
    const tr = document.createElement("tr");
    const td = document.createElement("td");
    td.innerHTML = err;
    tr.appendChild(td);
    resultContainer.appendChild(tr);
  });
</script>