How to display specified number of data through link parameter? - javascript

I want to display from json server for example 5 of 100 objects. Is there any parameter like this one which sort?
const url = "http://localhost:8000/players?_sort=points&_order=desc";
const url = "http://localhost:8000/players?_sort=points&_order=desc";
let template = "";
fetch(url)
.then((res) => res.json())
.then((data) => {
data.forEach((player, idx) => {
template += `
<div class='modal-leaderboard__player-name'>
<h2>${idx + 1}. </h2>
<h2 data-player-rank>${player.name} </h2>
<h2 style='margin-left: auto'> <span data-points-rank>${player.points}</span> points</h2>
</div>
`;
});
this.rank.innerHTML += template;
});

if you mean fo example the first 5 items, can add a condition on var idx :
...
if(parseInt(idx)<6){
template+=...
....
this.rank.innerHTML += template;
}
...

Related

Can't get the images from an API to show up

I'm using an API to get information for a database sort of thing. I want the images to be displayed to the right of the text but the images aren't showing up at all. I tried multiple different keys and still nothing. Here is what it currently looks like:
The images are not showing up as you can see.
Here is the JS (its pulling the data from here https://api.tvmaze.com/shows/347/episodes):
// DATABASE const sunnyList = document.getElementById('sunnyList'); let sunnyInfo = [];
searchBar.addEventListener('keyup', (e) => { const searchTarget = e.target.value.toLowerCase(); const filteredSunny = sunnyInfo.filter(sunny => {
return sunny.name.toLowerCase().includes(searchTarget) || sunny.airdate.toLowerCase().includes(searchTarget) || sunny.airtime.includes(searchTarget) });
displayInfo(filteredSunny); });
const loadLayout = async () => {
try {
const res = await fetch('https://api.tvmaze.com/shows/347/episodes');
sunnyInfo = await res.json();
displayInfo(sunnyInfo);
} catch (err) {
console.error(err);
} };
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src="${sunny.image}"></img>
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };
loadLayout();
I've tried sunny.image.medium and sunny.image.original but it still doesn't show up.
Any help is appreciated :)
The image is not a url string, but an object with the following shape:
{
medium: string,
original: string
}
where both strings contain the actual image URLs.
For your use case medium probably makes more sense, so you can do this:
<img src="${sunny.image?.medium}"></img>
Edit
Added optional chaining because some items do not have image property.
The problem your are facing is that not all objects have images.
Please try this code:
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
const img = sunny.image ? sunny.image.medium : "https://picsum.photos/200/300"
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src=${img} />
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };

Why when i am searching for something else is deleting the previous contents

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.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;
});
}
It's because you are replacing the contents in the mealList element every time.
A simple workaround would be to retrieve the the innerHTML values before you update it.
Something like
let html = mealList.innerHTML;
rather than starting off empty every time you call the function should do the trick.

Getting Null when trying to query the path to my button element

Issue:
I want to return the button Element within my document that matches the specified selector, in this case ".comment-body__interaction--delete" but keep getting a return of null every time I console.log the variable that contains the return element.
Background Info
The HTML element I'm Trying to target has been inserted into the document via innerHTML.
All my scripts are at the bottom of the index.html page
I'm using querySelector at the bottom of the js document.
I know my class name is correct because I can style it via CSS.
my code
// LOCATION VARIABLES ***
const conversation = document.querySelector('.conversation-container-posted');
const form = document.querySelector('form');
console.log(form);
// Array THAT HOLDS ALL MY COMMENT OBJECTS
let objectsArray;
// VARIABLE THAT HOLDS MY HTML TEMPLATE
const template = (singleCommentObj) => {
return `
<article class="comment-container">
<figure class="comment-container__picture">
<img class="comment-container__picture-img" src="${singleCommentObj.image}" alt="profile picture" />
</figure>
<div class="comment-body">
<h3 class="comment-body__name">${singleCommentObj.name}</h3>
<div class="comment-body__date">${singleCommentObj.date}</div>
<article class="comment-body__comment"><p>${singleCommentObj.comment}</p></article>
<div class="comment-body__interaction">
<div class="comment-body__interaction--likes">Likes</div>
<button id="${singleCommentObj.id}" class="comment-body__interaction--delete">Delete</button>
</div>
</div>
</article>
<hr class="comment-container__divider"/>
`;
};
const displayComment = (object) => {
let staticComments = object
.sort((a, b) => b.timestamp - a.timestamp)
.map((values) => {
values.image = 'https://loremflickr.com/48/48';
values.date = moment.unix(values.timestamp / 1000).fromNow();
return template(values);
})
.join('');
conversation.innerHTML = staticComments;
};
// Gets AN ARRAY OF OBJECTS FROM THE api AND ASSIGNS IT TO objectsArray
// CALLS displayComment WITH objectsArray AS A PARAMETER TO INSERT ITS CONTENT INTO THE DOM
axios
.get('https://project-1-api.herokuapp.com/comments?api_key=7d8d085e-486e-42dc-b836-58009cbfa68f')
.then((response) => {
objectsArray = response.data;
displayComment(objectsArray);
})
.catch((error) => {
console.log(error);
});
form.addEventListener('submit', (e) => {
e.preventDefault();
let fluidObject = new FormData(e.target);
fluidObject = Object.fromEntries(fluidObject);
axios
.post('https://project-1-api.herokuapp.com/comments?api_key=7d8d085e-486e-42dc-b836-58009cbfa68f&content-type=application/json', {
name: fluidObject.name,
comment: fluidObject.comment,
})
.then((response) => {
objectsArray.push(response.data);
displayComment(objectsArray);
})
.catch((error) => {
console.log(error);
});
});
// DELETE
const a = document.querySelector('.comment-body__interaction--delete');
console.log(a);
This console.log(a) returns NULL
The code that creates the said element, displayComment is in an asynchronous actions callback.
You have to wait for the action to complete before you try to access the element.
In other words const a = document.querySelector('.comment-body__interaction--delete'); executes before your request was successful and the elements were created.

Json file struggling with the length

So, i got everything almost working as i want it, just a mistake that im struggling. Everytime i search for an item, when the result for that item shows the length is repeated.
When i search for ox there are 2 results and that is correct, but the length (2) shows in both of them, i only display one
[Code]
const resultHtml = (itemsMatch) => {
if (itemsMatch.length > 0) {
const html = itemsMatch
.map(
(item) => `
<span>${itemsMatch.length}</span>
<div class="card">
<div class="items-img">
</div>
<div class="items-info">
<h4>${item.title}</h4>
<small>${item.path}</small>
</div>
</div>
`
)
.join('');
//console.log(html);
itemList.innerHTML = html;
}
};
////
Question 2
I got one more question, i was trying to get the image from the Json and what i got was the path haha
why the apth and not the img
const resultHtml = (itemsMatch) => {
if (itemsMatch.length > 0) {
const html =
`<span class="items-results">${itemsMatch.length} Resultados</span>` +
itemsMatch
.map(
(item) => `
<div class="card">
<div class="items-img">
${item.image}
</div>
<div class="items-info">
<h4>${item.title}</h4>
<small>${item.path}</small>
</div>
</div>
`
)
.join('');
console.log(html);
itemList.innerHTML = html;
}
};
If you move <span>${itemsMatch.length}</span> out of your map callback, it will not repeat for each item. Read more about map() here.
Replace:
const html = itemsMatch
.map(
(item) => `
<span>${itemsMatch.length}</span>
... more HTML here
`
)
.join('');
With this:
const html = `<span>${itemsMatch.length}</span>` + (
itemsMatch
.map(
(item) => `
<div class="card">
<div class="items-img">
</div>
<div class="items-info">
<h4>${item.title}</h4>
<small>${item.path}</small>
</div>
</div>
`
)
.join('')
);
Regarding your image issue:
You are just outputting the path and that's why it's printing out just the path. If you are trying to display an image then put the path as source of <img> tag.
So, instead of just:
${item.image}
Use:
<img src="${item.image}">

Generate n words from a json server by user input using Javascript

I just started to practice Javascript and I have a json file with a bunch of words. I want to display as many words as the given user input. If user input is 4 then 4 words will be displayed randomly from the server. I can successfully get the data from te server and display all of them in a table but the logic of displaying random words from the server is a little difficult for the firs try and I would like to get a better understanding how to approach it in my case. The getRandomWords() function is where I was trying to approach something.
words.json
{
"words":
[
"a",
"abandon",
"ability",
"able",
"abortion",
"about",
"above",
"abroad",
"absence",
"absolute",
"absolutely",
"absorb",
"abuse",
"academic"
]
}
snippet from project.js
function getServerData(url) {
let fetchOptions = {
method: "GET",
mode: "cors",
cache: "no-cache"
};
return fetch(url, fetchOptions).then(
response => response.json(),
err => console.error(err)
);
}
document.querySelector("#server-button").addEventListener("click", function() {
getServerData("http://localhost:3000/words").then(
data => fillDataTable(data, "wordTable")
);
});
function getRandomWords() {
let words = getServerData("http://localhost:3000/words").then(
data => randomWordExample(data)
);
var howManyWords = document.querySelector("#words-to-memorize");
const randomElement = words[Math.floor(Math.random() * words.length)];
console.log("random words: ", randomElement);
}
index.html
<div class="row">
<div class="col-2"></div>
<div class="col-8">
<div class="form-group">
<label for="words-to-memorize">How many words you want to see?</label>
<input type="text" class="form-control" id="words-to-memorize">
</div>
<button id="get-words-button" class="button btn btn-block btn-primary">
Get the words
</button>
</div>
<div class="col-2"></div>
</div>
function getRandomWords () {
let words = getServerData("http://localhost:3000/words").then(
data => randomWorldExample(data)
);
let howManyWords = document.querySelector("#words-to-memorize");
let randomElement = words[0].words.sort(() => 0.5 - Math.random())
console.log("random words: ", randomElement.slice(0, howManyWords));
}
This should get ya there. What we are doing is randomly sorting the array then we are slicing the array to the n value.
My working solution finally was the following:
function getRandomWords() {
let words = getServerData('http://localhost:3000/words').then(data => {
const wordsToMemorize = document.querySelector('#words-to-memorize');
document.querySelector("#wordsInput").addEventListener("click", function() {
let temp = wordsToMemorize.value;
selectedtombelemek.innerHTML = "";
for(let i = 0; i < temp; i++) {
let rander = Math.floor(Math.random() * 3000);
selectedtombelemek.innerHTML += data[rander] + "</br>";
}})
});
}

Categories