pedaars
pedaars

Reputation: 161

Returning data from my JavaScript function

I have been having issues getting the data I am requesting to display correctly it was being displayed as undefined.

 fetch(url)
.then(res => res.json())
.then((manager) => {
/* console.log(manager); */ 
    for (i in manager.data){
        var row = $('<div id="Data">' + '<br>' + getLogo(manager, i) + '<br>'
                + '<br>' + '<p1>' + getName(manager, i) + '</p1>'   
                + getAdd1(manager, i) + getAdd2(manager, i) + getAdd3(manager, i) 
                + getCity(manager, i) + getPcode(manager, i) 
                + '<br>' + getCountry(manager, i) + '<br>' 

My issue is with the call to getCountry

                + '<br>' + getWeb(manager, i) + '<br>' 
                + '<br>' + getPhases(manager, i) 
                + '<br>' + getPspon(manager, i) 
                + '<br>' + getOspon(manager, i) + '<br>'
                + '<br>' + getDesc(manager, i) + '<br>' 
                + '<br>' + '</div>' + '<br>');

        $('#Results').append(row);
    }           
})
};

After some research I think the problem was that the getCountry method is so long it carries on with the rest of the code and displays it as undefined.

I then came across Promises and tried to add this to the function but now the html page just shows [object Promise]. The getCountry function is shown below and was the same before the addition of the Promise code.

This is what I am trying to achieve

Checks that there is an address and then checks for a country code. Assigns the 3 digit numerical country code to country. Then loads a JSON containing ISO 3166 data process this into a searchable object. Searches the objects for a match to the value stored in country. Then assigns the name field from the matched object to result and then returns it to be displayed at the end of the address.

function getCountry(manager, i){
    return new Promise(function(resolve, reject) {
        if(manager.data[i].attributes.addresses[0] != null && manager.data[i].attributes.addresses[0].country != null){
            var country = manager.data[i].attributes.addresses[0].country;
            var c = country.toString();
            let url = 'http://data.okfn.org/data/core/country-codes/r/country-codes.json';
            fetch(url)
            .then(res => res.json())
            .then((data) => {
            console.log(data);
            console.log(manager);
                        for(var i=0, length=data.length; i<length; i++){
                        if(data[i].M49 === c){
                            var result = data[i].name;
                            console.log(result);
                            Promise.resolve(result);

                        }
                    }
            })
        }
        else {
            var reason = " ";
            Promise.reject(reason);
        }
    }
    );
}

Where am I going wrong?

Updated code using @Zohaib Ijaz suggestion

fetch(url)
.then(res => res.json())
.then((manager) => {
/* console.log(manager); */ 
    for (i in manager.data){
        /* use a Promise in order to receive the result for the below function */
        getCountry(manager, i).then((cm)=> {
        var row = $('<div id="Data">' + '<br>' + getLogo(manager, i) + '<br>'
                + '<br>' + '<p1>' + getName(manager, i) + '</p1>'   
                + getAdd1(manager, i) + getAdd2(manager, i) + getAdd3(manager, i) 
                + getCity(manager, i) + getPcode(manager, i) 
                + '<br>' + cm + '<br>'
                + '<br>' + getWeb(manager, i) + '<br>' 
                + '<br>' + getPhases(manager, i) 
                + '<br>' + getPspon(manager, i) 
                + '<br>' + getOspon(manager, i) + '<br>'
                + '<br>' + getDesc(manager, i) + '<br>' 
                + '<br>' + '</div>' + '<br>');

        $('#Results').append(row);
        });
}
});
}

The getCountry function

function getCountry(manager, i){
    return new Promise(function(resolve, reject) {
    if(manager.data[i].attributes.addresses[0] != null && manager.data[i].attributes.addresses[0].country != null){
        var country = manager.data[i].attributes.addresses[0].country;
        var c = country.toString();
        let url = 'http://data.okfn.org/data/core/country-codes/r/country-codes.json';
        fetch(url)
        .then(res => res.json())
        .then((data) => {
                    for(var i=0, length=data.length; i<length; i++){
                        if(data[i].M49 === c){
                        var result = data[i].name;
                        /* console.log(result); */
                        resolve(result);
                        }
                        else {
                        var reason = "";
                        reject(reason);
                        }
                    }
        })
    }
    else {
        var reason = "";
        reject(reason);
    }

}
);
}

This is what I see in the Chrome console (24 times)

Uncaught (in promise) test.html:1

Upvotes: 2

Views: 103

Answers (2)

Arbauman
Arbauman

Reputation: 30

What I noticed is that you're calling Promise.resolve(result); when you instantiated the Promise at the start of the function, you passed it a function with two arguments, resolve and reject. Those are what you should be using to 'end' your Promise, so changing them to just resolve(result) and reject(reason) should let your Promise resolve properly.

That said, the point of a Promise is to say "do this, and when that's done, .then do this other thing". So you'd need something like

getCountry(manager, i).then(function(result) {
    // result is whatever you passed into resolve() in getCountry
    // everything in here is done after getCountry finishes running
    // and returns a value 
}, function(rejection) {
    // rejection is whatever you passed into reject() in getCountry
    // this only happens if things didn't work
}

I'm not sure that Promises would work since you're calling the function in the middle of a concatenation. If your other functions make asyncronous calls, an alternative you might consider is to rewrite all of your asynchronous functions as Promises, then use Promise.all() to wait for all of them to resolve before proceeding to concatenate them into HTML. Something like this

var p1 = getLogo(manager, i);
var p2 = getName(manager, i);
var p3 = getAdd1(manager, i);
...

Promise.all([p1, p2, p3]).then(function(results) {
    results.join('<br>')
    // Whatever else you want to happen once all the functions are finished.
})

Upvotes: 1

Zohaib Ijaz
Zohaib Ijaz

Reputation: 22885

getCountry is not a synchronous function call. You need to wait for response.

fetch(url)
.then(res => res.json())
.then((manager) => {
/* console.log(manager); */ 
    for (i in manager.data){
        getCountry(manager, i).then((cm)=> {
          // Add other values as well. 
          var row = $('<br>' + cm + '<br>');
          $('#Results').append(row);
        });   
    }
 });

Upvotes: 0

Related Questions