Wikipedia project AJAX request with vanilla JS

Hi All,

I decided to try out a vanilla JS AJAX request after successfully using jQuery in the previous weather project. Well, after hours of banging my head I was able to get a variable to be inserted in the URL string based off of the user’s search but two weird things have occurred:

  1. You have to type the search twice to get the code to ‘stick’ when you initially load the page. Say you access the site and search dog. The search goes through and gets a response from the server but only populates my site with information on dogs for a split second before disappearing. If you type in dog again and hit enter the data sticks. You may also search for anything else thereafter and experience no problems. Why does the data disappear after the initial search?

  2. Once the data sticks, it’s in some kind of nested array structure despite “format=json” in the URL request. In a typical nested array you’d get pieces of code by inputting something like this: data[i][j], right? Well, that doesn’t work. In fact, the data the server sends back seems like it’s in one long string despite the brackets. Typing data[100] will return the 101st character in the long string of data. What makes things even more odd was that I tested out retrieving data from that array object on repl.it, and using the data[i] and data[i][j] methodology worked and retrieved the array’s elements and not just single characters (or not working in the case of data[i][j]. What gives? Has anyone else run into this problem before?

Anyways, here’s my code below. Note that the XMLHttpRequest is in a function that’s inside the clickedBtn function, which is an event listener to the search button on the website. clickedBtn readies the string to be sent to the inner getWiki function to be used in the URL request.

var textSearch = document.getElementById("text");
var searchBtn = document.getElementById("search");
searchBtn.addEventListener("click", clickedBtn);

function clickedBtn() {
  var rdyString = "";
  var len = textSearch.value.length;
  var queryString = textSearch.value;
  for (var i = 0; i < len; i++) {
    if (queryString[i] === " ") {
      rdyString += "%20";
    }
    else {
      rdyString += queryString[i];
   }
 }

 function getWiki() {
   var xhr = new XMLHttpRequest();
   xhr.open("GET", 'https://en.wikipedia.org/w/api.php?  action=opensearch&format=json&origin=*&search=' + rdyString, true);
   xhr.send();
   xhr.onreadystatechange = function() {
     if (xhr.readyState === 4 && xhr.status === 200) {
       var data = xhr.responseText;
       document.getElementById("test").innerHTML = data;
     }
   }
 }
 getWiki();
};

And here’s the codepen: http://codepen.io/FatherWeebles/pen/QGpZxb?editors=0010#0
Any advice/ideas?
Thank you!

This is always the first thing I do with every Wikipedia project I come across. Are you stalking me?

Your first problem is because buttons will, by default, fire the submit action which causes a page reload. The solution is to use preventDefault, a method on the event object passed into every handler.

In your case:

function clickedBtn(event) { // <-- add parameter here
  event.preventDefault(); // <-- call the method here
  var rdyString = "";
  var len = textSearch.value.length;
// ...
}

The second problem is because the Wikimedia API is tricky. I’ve got a link to the parameters I use for Wikipedia calls here, which will give you legit JSON.

1 Like

This sounded familiar to me but I wondered why I hadn’t been running into the same behavior all along. I think the answer is because if the <button> tag is not nested in a <form> tag the submit event won’t interfere.

That’s probably it. You may also have been using <input type="button">, which does not fire a submit event. You can also use <button type="button"> for the same effect.

Hah. Glad I’m not the only one who uses dog!

Thanks for taking the time to look into this. Indeed, once I added preventDefault problem #1 went away. And if I understand correctly, because the button is in a form, it will automatically submit the form which is why the data disappears. Once it gets submitted once, then my code runs as intended.

Your URL parameters also output something that looks more like JSON but had issues parsing the data with just the code block above. Ended up using JSON.parse(data) and assigned that to another variable.

Unfortunately it looks like the snippets are full of elements that are basically hyperlinks on the actually wikipedia site which end up showing up as “(disambiguation)” on my webpage. I can probably figure out how to remove the span elements and/or the disambiguation text with some regex research, but I wanted to ask how you’d use/edit the following snippet from the dog example - and I’m not asking for exact code here just how you would typically approach it:

"snippet": "A <span class=\"searchmatch\">dog</span> is a mammal. <span class=\"searchmatch\">Dog</span>     or dogs may also refer to:   Species in the family Canidae called &quot;dogs&quot; as a part of their common name: African wild <span class=\"searchmatch\">dog</span>, Lycaon"

Here’s the full JSON data:

For the HTML “special characters” (ex.: &quot;), here’s a clever trick

  1. in your logic, create a DOM element (textarea is ideal for this) but don’t actually add it to the page. It’s just in memory, not actually on the page.
  2. Then set its innerHTML to your string, with its special character gibberish.
  3. Then get the “cleansed” text back using .value

Basically, this renders the html special characters into their text equivalents and then extract it all back out. You’ll still need regex for the element tags…

EDIT - you can use .innerText instead of `.value’ for the same effect.

2 Likes

In this case, I think that the best code is no code at all. In my app, the snippet is rendered directly as HTML anyways, so the <span>s don’t matter and the encoded entities are actually beneficial. You can see my viewer here. If you search for something, then inspect one of the results, you can see the standard <span> has come along for the ride.

1 Like

Great, I’ll look into both of those suggestions. Thanks for the tips, guys!

I stumbled across a better API request. And because people may look in this thread later on for answers to the same problem I’d thought it’d be best to spell out a new option:

Here are the new URL request parameters:
xhr.open("GET", 'https://en.wikipedia.org/w/api.php? format=json&action=query&generator=search&gsrnamespace=0&gsrsearch=' + rdyString + '&gsrlimit=10&prop=extracts&exintro&explaintext&exsentences=1&exlimit=max&origin=*', true);

Note that rdyString is my variable, so name it whatever you like.

To make a very long story short, you have to get the keys by using Object.keys method (thank you intermediate algorithms) in order to incorporate each extract by capturing the pageID.

It looks cleaner and works like a charm now.

1 Like