Search code examples
javascriptjqueryhtmlajaxget

How to get data from http site into a html table using javascript?


I'm trying to get data from the following site: https://stryk.herokuapp.com/tipset As can be seen, the site seems to contain a list of objects. What I want to do is to get each object within {} in a row as separate columns (6 columns in total, one for gameNumber, one for teams and 3 for result in the following order 1 X 2 with a green checkmark for whatever the result for that game was). The table should update live when the results are updated on the original website.

My main issue is how do I get the data from the website in a managable format?

I've tried to use the jQuery $.get() Method, but maybe I'm not applying it correctly? Here is my current javascript code, I set the obj var as a test list, so I know that the "table-building" code works. The alert is just added to see what type of data I'm getting( seems to be a list of: [object, Object], [object, Object] .... and so forth, which I don't really understand)


  $.get("https://stryk.herokuapp.com/tipset", function(data, status){
    alert("Data: " + data + "\nStatus: " + status);
  });

var obj = $.get("https://stryk.herokuapp.com/tipset", function(data){
var globalCounter = 0;
var tbody = document.getElementById('tbody');
for (var i = 0; i < Object.keys(obj).length; i++) {
    var tr = "<tr>";

    tr += "<td>" + obj[i].gameNumber + "</td>" + "<td>" + obj[i].teams.toString() + "</td>" + "<td>" + obj[i].outcome + "</td></tr>";
    table.innerHTML += tr;
}
})

Html part, obs, I'm not allowed to change anything in the html and css part other than adding the script tag, they're just added here for reference.

<!DOCTYPE html>

<html>

<head>
    <title>JS - Examination</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="assets/css/index.css" />
    <link rel="shortcut icon" href="assets/img/fotboll.png" type="image/png">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script scr="assets/js/index.js" type="module"></script>
</head>

<body>

    <header>
        <h1>FOTBADSKOLLEN</h1>
        <p class="smallLogo">FÖR DIG SOM SPARKAR BOLL</p>
    </header>

    <nav>
        <ul>
            <li id="active"><a href="#">stryket</a></li>
            <li><a href="#">bänken</a></li>
            <li><a href="#">korvmojjen</a></li>
            <li><a href="#">lagen</a></li>
        </ul>
    </nav>


    <main>
        <h1>Stryk<img id="fotball" src="assets/img/fotboll.png"> tipset</h1>
        <p>-först till 13rätt vinner!</p>
        <hr />

        <table id="table">
            <tr>
                <th>Rad:</th>
                <th>Lag:</th>
                <th>1</th>
                <th>X</th>
                <th>2</th>
            </tr>
        </table>
    </main>

    <footer class="text-center">
        <nav>
            <ul>
                <li><a href="#">Kontakta oss</a></li>
                <li><a href="#">Om oss</a></li>
                <li><a href="#">Rapportera fel</a></li>
            </ul>
        </nav>
        <h2>TIPSA OSS</h2>
        <p>
            Vi är ständigt på jakt efter de senaste skvallren vad gäller fotbollsproffs och deras partners <br />
            Har du ett tips eller kanske filmat något själv? <br />
            Hör av dig via denna länken: <a href="#"> TIPSA OSS</a>
        </p>
        <br />
        <hr />
        <br />
        <p>
            Din väg från bänken rakt in i målet!<br>
            &copy; Fotbadskollen
            <script type="text/javascript">
                document.write(new Date().getFullYear());
            </script>
        </p>
    </footer>
</body>

</html>

Css part: Maybe it's not relevant?...


html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, caption {
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-size: 100%;
    vertical-align: baseline;
    background: transparent;
}

@font-face {
    font-family: FjallaOne-Regular;
    src: url("../fonts/FjallaOne-Regular.otf") format("opentype");
}

html {
    background: url('../img/bg.jpg') #fff no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
}

body {
    font-family: Verdana;
    color: #000;
}

header {
    height: 100px;
    color: #000;
    text-align: center;
}

header p {
    font-size: 4em;
    width: 960px;
    margin: 0 auto;
}

.smallLogo {
    font-size: 2em;
    font-style: italic;
}

nav {
    margin-top: 60px;
    background-color: rgba(255, 255, 255, 0.9);
    height: 70px;
    text-transform: uppercase;
    font-weight: 400;
    letter-spacing: 2px;
    text-align: center;
}

ul {
    padding-top: 25px;
    list-style-type: none;
    text-align: center;
}

li {
    display: inline-block;
    margin-left: 40px;
}

a {
    color: #000;
    text-decoration: none;
}

#active a {
    color: red;
}

a:hover {
    text-decoration: underline;
}

main {
    background-color: rgba(255, 255, 255, 0.9);
    width: 960px;
    margin: 40px auto 0 auto;
    padding: 30px;
    text-align: center;
}

main table {
    margin: 0 auto;
    width: 92%;
    text-align: center;
}

main table tr td:first-child, main table tr th:first-child {
    text-align: left;
}

#fotball {
    opacity: 1;
}

.checkmark {
    display: inline-block;
    width: 22px;
    height: 22px;
    -ms-transform: rotate(45deg);
    /* IE 9 */
    -webkit-transform: rotate(45deg);
    /* Chrome, Safari, Opera */
    transform: rotate(45deg);
}

.stem {
    position: absolute;
    width: 5px;
    height: 11px;
    background-color: green;
    left: 11px;
    top: 6px;
}

.kick {
    position: absolute;
    width: 5px;
    height: 5px;
    background-color: green;
    left: 8px;
    top: 12px;
}

main hr {
    margin: 40px;
}

main p {
    padding-left: 250px;
}

.text-center {
    text-align: center;
}

.text-bold {
    font-weight: bold;
}

footer {
    background-color: rgba(255, 255, 255, 0.9);
    padding-bottom: 25px;
}

footer nav {
    background-color: transparent;
}

footer hr {
    max-width: 960px;
}

table {
    text-align: left;
}

hr {
    height: 0;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
    border: 0;
    border-top: 1px solid #999999;
}

.red {
    color: red;
}

h1, h2, nav, header {
    font-family: FjallaOne-Regular;
}

h1 {
    font-size: 4em;
}

h2 {
    font-size: 1.5em;
}

footer h2 {
    color: red;
}

I'm simply not getting any updates on my html site table, I want it to be updated live upon updates on the source webbpage. I also would like to have a green checkmark for the results instead of the numbers with the following code:

<span class="checkmark">
            <div class="stem"></div>
            <div class="kick"></div>
        </span> 

But how should this be included in the javascript?


Solution

  • There are a couple of different issues in your question. I'll take the data acquisition part on its own for the moment, then discuss the automatic-updating aspect at the end.

    Firstly, you don't need to use jQuery for this. You can use JavaScript's promise-based fetch functionality to retrieve the contents of the page, parse it as a JSON object, and format the values within the resulting array, all asynchronously. You can do this like so:

    const table = document.getElementById("tipset");
    const td = document.createElement("td");
    const tr = document.createElement("tr");
    
    // Define the order in which the columns appear in the table.
    const cols = ["gameNumber", "teams"];
    const outcomes = ["1", "X", "2"];
    
    // Fetch the contents of the page
    fetch("https://stryk.herokuapp.com/tipset")
      .then(r => r.json()) /* Convert the contents to JSON */
      .then(e => {
        // For each of the items in the array...
        e.forEach(i => {
          // Clone the reference tr object defined at the top.
          let row = tr.cloneNode();
          // For each of the predefined columns...
          cols.forEach(l => {
            // Clone the reference td object defined at the top.
            let cell = td.cloneNode();
            // Set the contents to the value in the object, or "-" if missing.
            cell.textContent = i[l] || "-";
            // Append the cell to the row.
            row.appendChild(cell);
          });
          // For each of the outcomes defined near the top...
          outcomes.forEach(o => {
            // Clone the reference td object defined at the top.
            let cell = td.cloneNode();
            // If the outcome of the current object is equal to the current outcome in the array...
            if (i.outcome === o) {
              // Place a green checkmark in the array.
              cell.textContent = "\u2714\uFE0F";
            }
            // Append the outcome cell to the row.
            row.appendChild(cell);
          });
          // Append the completed row to the table.
          table.appendChild(row);
        });
      });
    <table id="tipset">
      <tr>
        <th>gameNumber</th>
        <th>teams</th>
        <th>1</th>
        <th>X</th>
        <th>2</th>
      </tr>
    </table>

    It's important to use cloneNode here instead of just creating a string of HTML. Why? Because you don't necessarily control the names of the teams. If a football team decides to name themselves <script>alert(1)</script> and you directly add that name to your page, you have a textbook XSS vulnerability. Using Element#textContent will automatically escape these names, which removes the risk of XSS.

    Now, the code above works, but it doesn't auto-update. The reason for this is that you really shouldn't be re-creating a table every time data updates. The only alternative to remaking the table would be to make the full request and diff the contents of the object to see if anything changed. Not only will this strategy put a strain on the third party data provider (because every client is requesting the data again and again, however often you want to update), but it's just more effort than it's worth.

    I'd recommend taking a look at HTTP Long Polling or WebSockets to enable live updating of data. Both of these are purpose-built for dynamic data retrieval, whereas $.getJSON and fetch aren't.