0
  1. I am trying to use JSON data from "https://www.purpleair.com/json?show=13165" and put the data on my website.
  2. I am trying to access the JSON field name "Stats" and I am trying to get the sub-field name ' \"v\" '. Here is the documentation provided by purpleair. https://docs.google.com/document/d/15ijz94dXJ-YAZLi9iZ_RaBwrZ4KtYeCy08goGBwnbCU/edit (second page)

I have my code written using a XMLHttpRequest(). It says at W3Schools that you cant go across domains, and when I tried to follow their instructions using PHP, I got lost. I do not own the purpleair.com

<!DOCTYPE html>
<html>
<head>
    <title>Your Page Title</title>
</head>

<body>
    <h1>Hello</h1>
    <p id='demo'></p>
    <script src="jsonp.php">
        function reqListener() {
            var myObj = JSON.parse(this.responseText);
            document.getElementById("demo").innerHTML = myObj.stats
        }
        function loadData() {
            var oReq = new XMLHttpRequest();
            oReq.addEventListener("load", reqListener);
            oReq.open("GET", "https://www.purpleair.com/json?show=13165");
            oReq.send();
        }
        loadData()
    </script>
</body>
</html>
  • 1
    This question is similar to https://stackoverflow.com/questions/21715620/using-jsonp-to-get-json-data-from-another-server – Shravani Jul 02 '19 at 19:18

2 Answers2

0

You can get JSON from PurpelAir like this:

function reqListener() {
  // parse the the data
  var data = JSON.parse(this.responseText)
  // create an array from the required data (result.Stats -> watch the capital 'S')
  var mappedData = data.results.map(item => item.Stats)
  // display data
  document.getElementById('demo').innerHTML = mappedData.join()
}

function loadData() {
  var oReq = new XMLHttpRequest();
  oReq.addEventListener("load", reqListener);
  oReq.open("GET", "https://www.purpleair.com/json?show=13165");
  oReq.send();
}

loadData()
<h1>Hello</h1>
<p id="demo"></p>

More about XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

I reworked your code below:

<!DOCTYPE html>
<html>

<head>
  <title>Your Page Title</title>
</head>

<body>
  <h1>Hello</h1>
  <!-- make ' to " in the ID-->
  <p id="demo"></p>
  <!-- no src for the script -->
  <script>
    function reqListener() {
      var myObj = JSON.parse(this.responseText);
      // this myObj.stats doesn't exist (try console.log(myObj))
      document.getElementById("demo").innerHTML = myObj.stats
      // instead try this:
      document.getElementById("demo").innerHTML = myObj.results.map(item => item.Stats).join()
    }

    function loadData() {
      var oReq = new XMLHttpRequest();
      oReq.addEventListener("load", reqListener);
      oReq.open("GET", "https://www.purpleair.com/json?show=13165");
      oReq.send();
    }
    loadData()
  </script>
</body>

</html>
muka.gergely
  • 8,063
  • 2
  • 17
  • 34
  • How I tried to have the code come out as the ID 'demo', but that isnt working. I posted my new code as an edit. Any tips? –  Jul 02 '19 at 19:24
  • Thank you so much. I got the JSON data. –  Jul 02 '19 at 19:33
  • 1. The ` – muka.gergely Jul 02 '19 at 19:34
  • I'm happy that I could help :) – muka.gergely Jul 02 '19 at 19:36
  • Okay. Where should I put the myObj.results[0].Stats? –  Jul 02 '19 at 19:42
  • Would you mind looking at one of my other projects? https://stackoverflow.com/questions/57398435/how-can-i-get-data-from-a-json-file-that-is-on-a-different-domain-with-no-header –  Aug 09 '19 at 19:23
0

Note that the Stats property is JSON-encoded inside the other JSON-encoded results.

Here is another way to deal with it, using the more modern fetch in place of XHR:

const getData = () =>
  fetch('https://www.purpleair.com/json?show=13165')
    .then(res => res.json())
    .then(json => json.results)
    .then(res => res.map(r => JSON.parse(r.Stats)))
    .then(res => res.map(r => r.v))

getData()
  .then(vs => document.getElementById('output').innerHTML = vs)
#output {background: yellow; padding: .25em}
<h1>Test</h1>
<p>Stats v values: <span id="output"></span> 

Update: Explanation

A comment asked how this works.

First off, there's some unfortunate overlap in naming. res or result or results is a common name for the result of a server call. The res in res => res.json() represents that. But then we take this object (which I called json, not a very good name, admittedly; it also probably should be res, but we have a surfeit of ress already) and extract its results property to pass to the next .then() call. I also call this variable res in the next callback. Finally, the last call .then() was stupidly named. It should read

    .then(stats => stats.map(s => s.v))

So it might also be written,

const getData = () =>
  fetch('https://www.purpleair.com/json?show=13165')
    .then(serverResponse => serverResponse.json())
    .then(apiResultObject => apiResultObject.results)
    .then(results => results.map(result => JSON.parse(result.Stats)))
    .then(stats => stats.map(stat => stat.v))

All the thens have to do with the Promise API. If you're not used to it, it is definitely worth spending some time investigating.

The two map calls are used to convert one array into another by collecting the results of running a given function on each element. So

          results => results.map(result => JSON.parse(result.Stats))

means that for each element in the array results, we will create a new element by taking its Stats property and running JSON.parse on that value. Then we will put all these values together in a new array. JSON.parse takes the string value returned by the API and turns it into a JS object. We need this here, even though we've done a JSON call on the response object because of the slightly unusual structure of the response where this part is double-encoded.

Similarly, this line:

          stats => stats.map(stat => stat.v)

converts an array of stats objects into an array containing their v properties.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • Thank you. Could you explain what ```res.map(r => JSON.parse(r.Stats)))``` and ```res.map(r => r.v))``` are doing? Also, What does 'r' stand for? Sorry, I am new to this. –  Jul 02 '19 at 20:46
  • @BrianWiebe: Updated with an more complete explanation. – Scott Sauyet Jul 03 '19 at 01:10
  • Thank you. That makes a lot more sense. The ```v``` is relating to the array that was mapped. However, using the ID that I am using, I there are two JSON arrays in ```result```. How can I get rid of the second ```v``` value? –  Jul 03 '19 at 14:48
  • This is easier. Untested, but it should be something like this: `... .then(apiResultObject => apiResultObject.results[0]).then(result => JSON.parse(result.Stats)).then(stat => stat.v)` ` – Scott Sauyet Jul 03 '19 at 14:59
  • Would you mind taking a look at another project I am doing? https://stackoverflow.com/questions/57398435/how-can-i-get-data-from-a-json-file-that-is-on-a-different-domain-with-no-header –  Aug 09 '19 at 19:23
  • @wiebecoding: sorry, I'm on vacation for the rest of the week with no access to a computer. – Scott Sauyet Aug 12 '19 at 13:40
  • No problem. Have fun @ScottSauyet. –  Aug 12 '19 at 15:41
  • Is it possible to get the AGE from the regular ```results[0].AGE```? I cant seem to find a way to get the value in the first place. Also, is it possible to have an if statement that does ```.then(vs => document.getElementById('GBPM').innerHTML = vs.toFixed(2))``` when the age is under 10 and to do ```.then(vs => document.getElementById('GBPM').innerHTML = "-Offline-"``` when the age is over 10. –  Sep 22 '19 at 18:00