1
var listApi = document.querySelector(".list-item")
var searchApi = document.getElementById("search-api")
document.querySelector("#enter").addEventListener("click", e => {
    e.preventDefault();
    var inputValue = searchApi.value; 
    fetch('https://wft-geo-db.p.rapidapi.com/v1/geo/cities/'     +inputValue, options)
    .then(response => response.json())
    .then(response => console.log(response))
    .then((data) => {
        var title = document.createElement("li")
        title.setAttribute = ".list-item";
        title.innerText = data;
    })
    .catch(err => console.error(err));

});

//Html portion

<h2 class="justify-center flex">Results</h2>
<ul id="result-list">
  <li class="list-item "></li>

</ul>

The api works fine as it displays the data in the console, i just can figure how to get it in my html.

R S
  • 25
  • 4
  • What kind of data does the API return? JSON that when parsed is an array, an object? – Andy Apr 06 '22 at 14:52
  • It returns a object with data that has an array. Im not sure if im saying it correctly, but when it displays in the console it says object when I click the object drop down it shows data with an array of information. – R S Apr 06 '22 at 15:03

3 Answers3

1

When you create an element with document.createElement it exists only in memory-- it isn't actually attached to the DOM yet. You need to insert it somewhere, like so:

var listApi = document.querySelector(".list-item")
var searchApi = document.getElementById("search-api")
document.querySelector("#enter").addEventListener("click", e => {
    e.preventDefault();
    var inputValue = searchApi.value; 
    fetch('https://wft-geo-db.p.rapidapi.com/v1/geo/cities/'     +inputValue, options)
    .then(response => response.json())
    .then(response => console.log(response))
    .then((data) => {
        var title = document.createElement("li")
        title.setAttribute = ".list-item"
        title.innerText = data;
        var list = document.getElementById("result-list");
        list.appendChild(title);
    })
    .catch(err => console.error(err));

});

Also note your line title.setAttribute = ".list-item" won't work as you expect-- you are overwriting the setAttribute function with a string. Better to just use classList as title.classList.add('list-item');

Also, as user Andy points out in the comments, you have another problem with your chaining of .thens-- specifically, you have a .then() that console.logs the result and returns nothing. The way promise chains work is that the next .then will act on the result passed from the previous .then; however, .then(response => console.log(response)) will return undefined, so the data argument coming into your next .then will be undefined. Below is a code example that fixes both the setAttribute issue and the .then issue:

var listApi = document.querySelector(".list-item")
var searchApi = document.getElementById("search-api")
document.querySelector("#enter").addEventListener("click", e => {
    e.preventDefault();
    var inputValue = searchApi.value; 
    fetch('https://wft-geo-db.p.rapidapi.com/v1/geo/cities/'     +inputValue, options)
    .then(response => response.json())
    .then(response => {
        console.log(response);
        return response;
    })
    .then((data) => {
        var title = document.createElement("li")
        title.classList.add("list-item");
        title.innerText = data;
        var list = document.getElementById("result-list");
        list.appendChild(title);
    })
    .catch(err => console.error(err));

});

Finally, if you are just attempting to insert a plain object or array as text into the DOM you will likely get unexpected results, such as it displaying simply as "object Object" in the <li>. Let's presume for a moment that your response looks something like this:

{
    data: ['MacReady', 'Childs', 'Blair', 'Nauls', 'Clark', 'Palmer']
}

To write this data to the DOM, you'd need to access it at the data property, then map over it (either with a loop or using an array method like .forEach) and add each item to an element (like an <li> in your case) and insert it to the DOM. Here's an example:

var listApi = document.querySelector(".list-item")
var searchApi = document.getElementById("search-api")
document.querySelector("#enter").addEventListener("click", e => {
    e.preventDefault();
    var inputValue = searchApi.value; 
    fetch('https://wft-geo-db.p.rapidapi.com/v1/geo/cities/'     +inputValue, options)
    .then(response => response.json())
    .then(response => {
        console.log(response);
        return response;
    })
    .then((data) => {
        let myList = data.data;

        myList.forEach(datum => {
            var title = document.createElement("li")
            title.classList.add("list-item");
            title.innerText = datum;
            var list = document.getElementById("result-list");
            list.appendChild(title);
        });
    })
    .catch(err => console.error(err));

});

There are other approaches to this-- using a for loop, or using DOM fragments to increase performance, but something along these lines should work for your use case.

Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
  • 1
    `.then(response => console.log(response))` is also an issue. – Andy Apr 06 '22 at 14:44
  • 1
    @Andy - ah, good point-- I'll update my answer to call that out-- thanks! – Alexander Nied Apr 06 '22 at 14:52
  • Thanks for the help, this works, just that now my html displays [object Object] and im not sure what that is – R S Apr 06 '22 at 15:07
  • @RS - that most likely means the data you are receiving is a [JavaScript `Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object). It is probably an array or a plain object-- both of these are data structures that can contain information in a structured manner that allows you to easily manipulate and access the data they contain. As a simplification, plain objects are hash maps accessed by key, whereas arrays are ordered lists. – Alexander Nied Apr 06 '22 at 15:11
  • Ultimately, if you try to push a non-string into the DOM it will get converted to a string, sometimes inelegantly. You could try doing it as `title.innerText = JSON.stringify(data);` to get a sense of what is actually contained within, but I imagine you already know this from your console log in the previous `.then`. You will probably need to figure out what data you want to display and how to best extract it from the response. This is most likely sufficiently different a task from the question in your post here that it may be better posted as a separate question. – Alexander Nied Apr 06 '22 at 15:13
  • @RS - Actually, [your question about "object Object" almost certainly already has several answers on SO already](https://stackoverflow.com/q/55198186/6831341). – Alexander Nied Apr 06 '22 at 15:16
  • @Andy -- ah, sure, thanks, I can update that now. – Alexander Nied Apr 06 '22 at 15:17
  • @AlexanderNied I wouldn't use `map` for that as it's intended to return a new array. `forEach` or `for/of` would be better. But great answer. – Andy Apr 06 '22 at 15:32
  • 1
    @Andy Ooof-- great point. I was looking at some React code, which typically uses `.map` in JSX, and went on autopilot-- I like to think I would have caught that on PR review :D Thanks for all the double-checks! – Alexander Nied Apr 06 '22 at 16:13
  • When I try this method I keep having an error TypeError: undefined is not a function (near '...myList.forEach...' – R S Apr 06 '22 at 16:57
  • @RS - my example assumed a format for your data since you didn't provide it in your question. If the format of your data doesn't _exactly_ match my assumption it won't work as a direct copy/paste; it was intended to provide you with enough context to extrapolate it into your own specific use case. – Alexander Nied Apr 06 '22 at 17:32
  • Thanks @AlexanderNied I figured it out because of your response – R S Apr 06 '22 at 17:40
1

The only missing part is how you loop over your data and add items to your list, so here's a quick example.

// Cache the list element
const ul = document.querySelector('ul');

// Your data will look something like this
// where `data` is an object with a property
// with an array
const data = {
  cities: [
    { name: 'London' },
    { name: 'Paris' }    
  ]
};

// Once your data has returned, loop
// over the array, and then add each new item
// to the list
for (const city of data.cities) {
  const item = document.createElement('li');
  item.textContent = city.name;
  ul.appendChild(item);
}
<ul></ul>

If you wanted another approach that uses more "modern" methods:

// Cache the list element
const ul = document.querySelector('ul');

// Your data will look something like this
// where `data` is an object with a property
// with an array
const data = {
  cities: [
    { name: 'London' },
    { name: 'Paris' }    
  ]
};

// Create an array of HTML strings by mapping
// over the data
const html = data.cities.map(city => {
  return `<li>${city.name}</li>`;
}).join('');

// And then adding that joined string to the list
ul.insertAdjacentHTML('beforeend', html);
<ul></ul>

Addition information

Andy
  • 61,948
  • 13
  • 68
  • 95
0

You need to update an element that is in the dom.

var listApi = document.querySelector(".list-item")
var searchApi = document.getElementById("search-api")
document.querySelector("#enter").addEventListener("click", e => {
    e.preventDefault();
    var inputValue = searchApi.value; 
    fetch('https://wft-geo-db.p.rapidapi.com/v1/geo/cities/'     +inputValue, options)
    .then(response => response.json())
    .then(response => console.log(response))
    .then((data) => {
        listApi.innerText = data;
    })
    .catch(err => console.error(err));

});
Mohamed Abdallah
  • 796
  • 6
  • 20