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 res
s 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 then
s 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.