I'm pretty new when it comes to working with Api's. I'm trying to query the URL string and return some Gifs.
const gifForm = document.querySelector("#gif-form");
gifForm.addEventListener("submit", fetchGiphs);
function fetchGiphs(e) {
e.preventDefault();
const searchTerm = document.querySelector("#search").value;
fetch(`https://api.giphy.com/v1/gifs/search?&q=${searchTerm}&limit=100&api_key=3mIxmBZUIIPyb8R69gtxaW8Hsh74dFKV`)
.then((response) => {return response.json(); })
.then(data => showGiphs(data.images.fixed_width.url))
.then(err => console.log(err));
}
function showGiphs(fixed_width) {
const results = document.querySelector("#results");
let output = '<div class="container">';
fixed_width.forEach((url) => {
console.log(url);
output += `
<img src="${data.images.original.fixed_width_url}"/>
`;
});
document.getElementById('results').innerHTML = output;
}
<form id="gif-form">
<input type="text" id="search">
<input type="submit" value="find">
</form>
<div id="results"></div>
If I remove the .then(data => showGiphs(data.images.fixed_width.url)) from the fetch and just console.log the data it's returning the search results that I want. However, when I try to map to the gif"data.images.fixed_width.url, I'm getting a console error of "Uncaught (in promise) TypeError: Cannot read property 'fixed_width' of undefined"
at fetch.then.then.data
Any help or push in the right direction would be awesome! Thank you! Also, if you'd like the view the demo you can view it here: https://codepen.io/Brushel/pen/jKgEXO?editors=1010
There is couple issues with your code.
The response from the API is an object, in this object there is data array, and each element in this array is information about each gif.
Try:
const gifForm = document.querySelector("#gif-form");
gifForm.addEventListener("submit", fetchGiphs);
function fetchGiphs(e) {
e.preventDefault();
const searchTerm = document.querySelector(".search").value;
fetch(`https://api.giphy.com/v1/gifs/search?&q=${searchTerm}&limit=100&api_key=3mIxmBZUIIPyb8R69gtxaW8Hsh74dFKV`)
.then((response) => {return response.json(); })
.then((resp => {
// Here we get the data array from the response object
let dataArray = resp.data
// We pass the array to showGiphs function
showGiphs(dataArray);
}))
.catch(err => console.log(err)); // We use catch method for Error handling
}
function showGiphs(dataArray) {
const results = document.querySelector(".results");
let output = '<div class="container">';
dataArray.forEach((imgData) => {
output += `
<img src="${imgData.images.fixed_width.url}"/>
`;
});
document.querySelector('.results').innerHTML = output;
}
<form id="gif-form">
<input type="text" class="search">
<input type="submit" value="find">
</form>
<div class="results"></div>
I hope this will help.
The response has a data property which is an array. If you want the first GIF in that array, that would look like this: data.data[0].images.fixed_width.url. So the full line would be .then(data => showGiphs(data.data[0].images.fixed_width.url)).
Related
I am learning to program and I want to do an asynchronous search. I got a code that works, but I do not understand why, I would like to know if anyone can help me to understand the code guide.
const list = document.getElementById("results");
const autoResults = (query) => {
fetch(`https://wagon-dictionary.herokuapp.com/autocomplete/${query}`)
.then(response => response.json())
.then((data) => {
data.words.forEach((result) => {
const resultLi = `<li>${result}</li>`;
list.insertAdjacentHTML("beforeend", resultLi);
});
});
};
const form = document.querySelector("#container input");
form.addEventListener("keyup", (event) => {
const inputText = event.currentTarget.value;
autoResults(inputText);
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<div id="container">
<input type="text" id="search" placeholder="Search">
<ul id="results" class="list-inline">
</ul>
</div>
Here is an improved version with comments
I use a debouncing method to not hammer the dictionary with a few letters
const list = document.getElementById("results");
const autoResults = (query) => {
fetch(`https://wagon-dictionary.herokuapp.com/autocomplete/${query}`) // call the site
.then(response => response.json()) // we get a JSON string back, parse it
.then((data) => { // here is a data object
list.innerHTML = data.words // here is an array of words
.map(word => `<li>${word}</li>`) // create a list using map
.join(''); // join to make a long string
});
};
const inputField = document.querySelector("#container input"); // it is a field, not a form
let tId, inputText; // make two global variables for timeout and text
inputField.addEventListener("input", (event) => { // input handles a paste too
const inputText = event.target.value;
// debounce
clearTimeout(tId); // stop any ongoing timeout
tId = setTimeout(() => autoResults(inputText), 300); // give the user 300 ms to type a letter
});
<div id="container">
<input type="text" id="search" placeholder="Search">
<ul id="results" class="list-inline">
</ul>
</div>
I need help by editing my code on how i can be able to display the data i have fetched from an external api and that from a local json file so that my card can show the user's avatar,name,occcupation,total number of impressions and total number of conversions on the same card.
Here is my code:
<script>
fetch("https://api.airtable.com/v0/appBTaX8XIvvr6zEC/tblYPd5g5k5IKIc98?api_key=key4v56MUqVr9sNJv")
.then((data)=>{
// console.log(data)
return data.json();
})
.then ((completedata)=>{
//console.log(completedata.records[0])
//an empty variable to catch the incoming data
let data1="";
// Then i added a html template to the data1 variable
completedata.records.forEach((values)=>{
data1+=`
<div class="card">
<span class="avatarLetter">${values.fields.Name.substr(0,1)}</span>
<p class="name">${values.fields.Name}</p>
<p class="occupation">${values.fields.occupation}</p>
</div> `;
});
document.querySelector("#card").innerHTML=data1;
})
.catch((error)=>{
console.log(error);
})
//pulling data from local json file
fetch('./logs.json')
.then((response) => {
return response.json();
})
.then((data) => {
// console.log(data);
let data1 = "";
let totalImpressions = 0;
let totalConversions = 0;
data.forEach((values) => {
totalImpressions += values.impression;
totalConversions += values.conversion;
data1 += `
<div class="card">
<p class="impression">${values.impression}</p>
<p class="conversion">${values.conversion}</p>
</div> `;
});
data1 += `<div>Total impressions = ${totalImpressions} Total conversions = ${totalConversions}</div>`;
document.querySelector("#card").innerHTML = data1;
})
.catch((error) => {
console.log(error);
})
</script>
When you write second time
document.querySelector("#card").innerHTML = data1;
you overwrite #card content.
The right way:
document.querySelector("#card").innerHTML += data1;
I have a chat program that adds an element to the dom when messaged. This element adds properly, but when I go to query it from the dom it shows as null. I do a fetch to the server just before, but it has an await to slow it down. Any ideas?
Here is my javascript code
socket.on('receive_message', async function(data) {
let messaged_user_li = document.getElementById('messaged_user_li'+data['from_user']);
console.log('messaged_user_li: '+messaged_user_li)
if (messaged_user_li == null) {
console.log('if fired')
await fetch('/get_messaged_user/'+data['from_user']).then((response) => {
response.json().then((data2) => {
loadMessagedUser(data2[0].id, data2[0].avatar, data2[0].username, data2[0].last_seen);
});
});
console.log(data['from_user'])
messaged_user_li = document.getElementById('messaged_user_li'+data['from_user']);
//despite this element being added this log shows nulls which causes issues later on in the code.
console.log('messaged_user_li: '+messaged_user_li)
}
let message_user = document.getElementById('message_user'+data['from_user']);
let message_target = document.getElementById("message_target"+data['from_user']);
if (messaged_user_li.classList.contains('active') == false) {
messaged_user_li.classList.add('flash-message');
}
if (message_user != null) {
data = `
<li class="clearfix">
<div class="message-data text-right">
<span class="message-data-time">just now</span>
</div>
<div class="message other-message float-right">`+data['message']+`</div>
</li>`;
message_target.innerHTML += data;
//Move scroller to bottom when message received
myDiv = message_user.querySelector(".chat-history");
myDiv.scrollTop = myDiv.scrollHeight;
}
});
You are only waiting for this promise to complete:
await fetch('/get_messaged_user/'+data['from_user']).then((response) => {
// ...
});
Not this one inside the callback:
response.json().then((data2) => {
loadMessagedUser(data2[0].id, data2[0].avatar, data2[0].username, data2[0].last_seen);
});
Which is why your code continues executing and trying to get the added element (which hasn't been added yet).
To solve this, you could chain the then calls:
await fetch('/get_messaged_user/'+data['from_user'])
.then((response) => response.json())
.then((data2) => loadMessagedUser(data2[0].id, data2[0].avatar, data2[0].username, data2[0].last_seen));
Or use await again:
const response = await fetch('/get_messaged_user/'+data['from_user']);
const data2 = await response.json();
loadMessagedUser(data2[0].id, data2[0].avatar, data2[0].username, data2[0].last_seen);
Why when you are searching for something else is deleting the previous contents ?For example first you search for egg and show the contents but then when you search for beef the program deletes the egg and shows only beef.Thank you for your time code:
const searchBtn = document.getElementById('search-btn');
const mealList = document.getElementById('meal');
const mealDetailsContent = document.querySelector('.meal-details-content');
const recipeCloseBtn = document.getElementById('recipe-close-btn');
// event listeners
searchBtn.addEventListener('click', getMealList);
mealList.addEventListener('click', getMealRecipe);
recipeCloseBtn.addEventListener('click', () => {
mealDetailsContent.parentElement.classList.remove('showRecipe');
});
// get meal list that matches with the ingredients
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
let html = "";
if(data.meals){
data.meals.forEach(meal => {
html += `
<div class = "meal-item" data-id = "${meal.idMeal}">
<div class = "meal-img">
<img src = "${meal.strMealThumb}" alt = "food">
</div>
<div class = "meal-name">
<h3>${meal.strMeal}</h3>
Get Recipe
</div>
</div>
`;
});
mealList.classList.remove('notFound');
} else{
html = "Sorry, we didn't find any meal!";
mealList.classList.add('notFound');
}
mealList.innerHTML = html;
});
}
Beacuse you are using innerHTML , if you want to save the previous contents you should use append or innerHTML + = .
Because everytime you make a search, the html var is populated with new data.
if you move the 'html' variable to the root scope, this should get you there:
// get meal list that matches with the ingredients
let html = ""; // <-- place it outside the function body
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
// let html = ""; // <-- remove it from here
if(data.meals){
data.meals.forEach(meal => {
I've tried to retrieve a saved picture URL from Firebase Firestore, but I'm keep getting this error:
Uncaught (in promise) TypeError: Cannot read property 'picURL' of undefined.
I've tried a code, which you can see below. It's from "imgRef" and down.
HTML:
<div class="container">
<ul class="posts">
</ul>
</div>
JavaScript:
var postDocRef = db.collection('posts').doc(uid).collection('userPosts')
postDocRef.get().then(snapshot => {
setupPosts(snapshot.docs)
})
const posts = document.querySelector('.posts');
const setupPosts = (data) => {
let html = '';
data.forEach(doc => {
var docRefIDpost = docRef.id
const post = doc.data();
const li = `
<li>
<div class="title">${post.title}</div>
<div class="content">${post.content}</div>
<img class="img">
</li>
`;
var imgRef = db.collection('posts').doc(uid).collection('userPosts').doc(docRefIDpost);
imgRef.get().then(function(snapshot) {
const picURL = snapshot.data().picURL
if (picURL.exists) {
console.log(snapshot.data)
console.log(picURL)
var imgpost = document.querySelector(".img");
imgpost.src = picURL
}
})
html += li
})
posts.innerHTML = html;
}
});
The error is telling you that snapshot.data() returned undefined. As you can see from the API documentation, data() will return undefined when the requested document was not found. It's not clear here why, but your code should check for that first before accessing properties.
imgRef.get().then(function(snapshot) {
const data = snapshot.data()
if (data) {
const picURL = data.picURL
}
else {
// decide what you want to do if the document doesn't exist
}
})