Mikke.Learns

Connecting to a server with XMLHttpRequest, part 2

March 18th, 2019

In the type: entry-hyperlink id: c51CQOjspMxAYETAayywfBZ javascript object, we successfully connected to the server and got a response. In this part, we will explore this data, and try to display it on the webpage.

responsText and JSON.parse

As we figured out in the type: entry-hyperlink id: c51CQOjspMxAYETAayywfBZ, when readyState is 4 and status is 200, we know that we’ve got a connection to the server and have received a response.

We can explore this response with the read-only responseText or response property. These are very similar in usage, but the response is interpreted into an Array, a buffer, blob, document, JavaScript Object, or DOMString depending on the value of the XMLHttpRequest.responseType property. responseText, on the other hand, is the raw text.

We can use response when we get JSON from the server, and responseText if we receive a responseType in a format we don’t want to use.

If we take a look in the network tab again, we see that this API return the data as JSON.

xml2

So in this case, we can just use the response to fetch our data. If we log the data to the console, we see that we get a big chunk of text formatted as JSON.

xml2-2

To be able to use it, we need to turn it into a Javascript object. That’s done with the JSON.parse method.

let requestCharacter = function () { const url = 'https://pokeapi.co/api/v2/pokemon/1/'; const request = new XMLHttpRequest(); // When the ready state changes we use a function. // The function checks to see if ready state is 4 and status is 200. // If it is, we know that we have a connection, and we are ready to use the response data. request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) { let data = JSON.parse(request.response); console.log(data); } } request.open("GET", url, true); request.send(); }

If we now take a look at the console, we can see that the JSON.parse method has transformed the JSON data to a proper Javascript Object.

xml2-3

Math.random()

Since our URL has a 1 at the end…

const url = 'https://pokeapi.co/api/v2/pokemon/1/';

…we can see from the response data that the first Pokemon in the database is returned to us. It’s got an id of 1, and the name is “Bulbasaur”. If we change the URL to have a 2 at the end, we get the Pokemon with the id of 2, and the name “Ivysaur”.

xml2-4

I know that there are over 800 Pokemon in the PokeAPI database. To generate a random number we need to use the Math.Random function which can be used to generate a random integer between two numbers.

function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; } console.log(getRandomInt(1,808))

This function will return a number between 1 (the minimum is inclusive) and 807 (the maximum is exclusive). We can now use this function in our XMLHttpRequest.

let requestCharacter = function () { let randomNumber = getRandomInt(1, 807); const url = 'https://pokeapi.co/api/v2/pokemon/' + randomNumber; const request = new XMLHttpRequest(); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) { let data = JSON.parse(request.responseText); console.log(data); } } request.open("GET", url, true); request.send(); }

We generate a random number every time we call the server, and we combine the URL and the randomNumber variable to generate a random URL. As we can see, it works like a charm. Here we have requested six different Pokemon:

xml2-6

Now everything is ready for us to display some of this data on the webpage.

dot-notation

Since we’ve converted the JSON data to an object with key value pairs, we can access the properties of an object with a simple dot-notation. The screenshot above gives us a good overview of the object. I think I’ll start with the name, the id, height, weight the type, the abilities and an image.

Let’s first console log it:

let requestCharacter = function () { let randomNumber = getRandomInt(1, 807); const url = 'https://pokeapi.co/api/v2/pokemon/' + randomNumber; const request = new XMLHttpRequest(); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) { let data = JSON.parse(request.response); console.log(data.name); console.log(data.id); console.log(data.height); console.log(data.weight); console.log(data.types); console.log(data.abilities); console.log(data.sprites.front_default); } } request.open("GET", url, true); request.send(); }

Success! This is what we get:

xml2-7

Now we can add this to our webpage.

Updating the DOM

Now that we’ve got all the data we need from PokeAPI, we can use functions to update the webpage.

function updateData(data) { // Name name.innerText = data.name; // Type let types = 'Type: '; for (i = 0; i < data.types.length; i ++) { if ((i + 1) == data.types.length) { types += '<span>' + data.types[i].type.name + '</span>' } else { types += '<span>' + data.types[i].type.name + ' / </span>'; } } type.innerHTML = types; // Portrait portrait.src = data.sprites.front_default; // Abilities let pokeAbilities = 'Abilities: '; for (i = 0; i < data.abilities.length; i ++) { if ((i + 1) == data.abilities.length) { pokeAbilities += '<span>' + data.abilities[i].ability.name + '</span>' } else { pokeAbilities += '<span>' + data.abilities[i].ability.name + ' / </span>'; } } abilities.innerHTML = pokeAbilities; // Data divData.innerHTML = '<span>Height: ' + data.height + ', </span>'; divData.innerHTML += '<span>Weight: ' + data.weight + ', </span>'; divData.innerHTML += '<span>ID: ' + data.id + ', </span>'; } function loading() { name.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>'; type.innerHTML = ''; portrait.src = ''; abilities.innerHTML = ''; divData.innerHTML = ''; divData.innerHTML += ''; divData.innerHTML += ''; } function error() { name.innerHTML = '<span>Sorry, there was an error.</span>'; type.innerHTML = ''; portrait.src = ''; abilities.innerHTML = ''; divData.innerHTML = ''; divData.innerHTML += ''; divData.innerHTML += ''; }

This is what we get when the connection is successful:

xml2-8

If the connection is successful, the updateData function is invoked. But we also want a function for loading and if there is an error. To be able to invoke these at the right time, we need to take a look at the status codes again.

Loading and error

This is what our XML request looks like at the moment:

let requestCharacter = function () { let randomNumber = getRandomInt(1, 807); const url = 'https://pokeapi.co/api/v2/pokemon/' + randomNumber; const request = new XMLHttpRequest(); request.open("GET", url, true); request.send(); loading(); request.onreadystatechange = function () { if (request.readyState == 4 && request.status == 200) { let APIdata = JSON.parse(request.response); updateData(APIdata); } else if (request.status != 200) { request.onerror = error(); return; } } }

First we start the rotating icon to indicate that the process has started and is loading.

In the onreadystatechange callback function we are now also saying that if the status code is something other than 200, we will display an error message. So if we delete a part of the URL for testing, this is what we get:

xml2-9

That concludes this part of the XMLHttpRequest. But there is a lot more to learn. There are events we can use, and the newer fetch method and promises. This will be covered in a later post.

xml2-10