0

I am having problems in nesting ajax calls with jQuery to wikipedia api. The HTML is simple, just an input form and a button:

<input id='search-input' type="text" class="form-control">
 <button id="search-button" type="button" class="btn btn-primary">Search</button>
<div id ='outputDiv'></div>

THe search button has an event listener that fires a function that grabs data from wikipedia API:

...
searchBtn.addEventListener('click', searchwiki);
...
function searchwiki(){
    let searchTermObjects =[]

    let term = inputfield.value;

    let titleUrl = search_term(term);

    createWikiObject(titleUrl).then(function(){
        searchTermObjects.forEach(function(elem){
            addExtrctToObj(elem)
         })
    }).then(function(data){
        append_result(searchTermObjects)
    })

}


function createWikiObject(titleUrl){
    return $.ajax({
        type: "GET",
        url:  titleUrl,
        dataType : 'jsonp',
        async: true,
        error : function(ermsg){
            console.log('error in searching',ermsg)
        },}).then(function(data){

            for(let i = 0; i < data[1].length; i ++){
                searchTermObjects.push({
                    'title': data[1][i].replace(/\s+/g, '_'),
                    'description': data[2][i],
                    'url': data[3][i],
                })
            };  // this for loop should push each result as an object to an array named searchtTermObjects, and i am planning to use this array in the next ajax call to add another property named extract to each object in array
        }
    );  
}

function addExtrctToObj(obj){
    console.log(obj)
    return $.ajax({
        type: "GET",
        url:  get_text(obj['title']),
        dataType : 'jsonp',
        async: true,
        error : function(ermsg){
            console.log('error getting text',ermsg)
        }
    }).then(function (data){
        let pageID = Object.keys(data.query.pages);
        if(data.query.pages[pageID].hasOwnProperty('extract')){
            obj['extract'] = data.query.pages[pageID].extract;
        }
        // this function adds the extracted text for each article ,
        // the searchTermObjects now looks something like:
        / [{'title':...,'url':...,'description':...,'extract':..},{...}]

    })
};

function append_result(termsObjectsArray){
    // this function should loop through the searchtermobjects and append leading text for each object in the array to the Output div under the button

    for (let i = 0; i < termsObjectsArray.length; i++){
        let newDiv = document.createElement('div');

HOWEVER, Object.keys(termsObjectsArray[i]) returns only three keys at this time, and doesn't see the extract key'

        console.log(Object.keys(termsObjectsArray[i]))
        newDiv.classList.add('wiki-result');
        newDiv.innerHTML = termsObjectsArray[i]["extract"];

HERE is where i get error -- the inerHtml of newDiv has value UNDEFINED

        outputDiv.appendChild(newDiv);
    }
}



// the api calls are formed with these functions:
    let base_url = "https://en.wikipedia.org/w/api.php";
    function search_term(term) {
        let request_url = base_url + "?action=opensearch&search=" + term + "&format=json&callback=?";

        return request_url;
    }

    function get_text(term){
        let request_url = base_url + "?action=query&prop=extracts&exintro=&format=json&titles=" + term;  // explaintex=  returns plaintext, if ommited returns html

        return request_url;
    }

afetr I console.log(searchTermObjects) i get what i need, the array with objects that have all 4 properties with correct names, but I don't understand why the append_result function doesn't see the 'extract' key.

Next to the logged object in the console is the 'i' sign that says 'Value below was evaluated just now' , and there I have what I wanted -- every search result as an object with title, url, description, and extract keys.

copy this code to your IDE to see if you can help me with finding solution.

Barmar
  • 741,623
  • 53
  • 500
  • 612
MilošB
  • 1
  • 1
  • Objects and arrays in the console are "live" references to the actual object. Changes made to the object after you call `console.log()` will appear when you expand it. – Barmar Aug 13 '18 at 22:07
  • Don't use global variables to pass data around, use `resolve()` and pass the value to the next `.then()` function. – Barmar Aug 13 '18 at 22:09
  • Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Heretic Monkey Aug 14 '18 at 13:25

1 Answers1

0

I believe the issue you're having is that you're attempting to return a Deferred object, and there's nothing to return yet because of the deferral.

return $.ajax({
    type: "GET",
    url:  get_text(obj['title']),
    dataType : 'jsonp',
    async: true,
    error : function(ermsg){
        console.log('error getting text',ermsg)
    }
})

The async value is true, so the code is moving on before the request is finished, and you're getting a null value back.

Try setting async: false and see if you get a better response. As pointed out by Andrew Lohr in the comments, this is not a good way to solve the problem, it will only tell you if that is the problem.

If it is, then I would recommend not breaking the request up into multiple functions. You should just chain the AJAX calls, using the deferral approach. It would be structured like this:

$.ajax({ ... }).then(function(data){
    // ... do something with the data ...
    // Make your followup request.
    $.ajax({ ... }).then(function(data) {
        // ... finalize the response ...
    });
});

Also consider using the context option in the ajax call to pass in a callback method that can be fired once the chain is complete.

Jocko
  • 537
  • 2
  • 11
  • 1
    setting async false should not be a solution. the spec says it should be avoided and in some cases, it may even throw an error in the future due to the horrible experience to the end user. https://xhr.spec.whatwg.org/#sync-warning – Andrew Lohr Aug 13 '18 at 22:34
  • Fair point. I was suggesting the attempt to confirm that is the underlying cause. Will update my answer. – Jocko Aug 13 '18 at 22:35