setInterval on Axios get and Update Output Without Repeating - javascript

I am making a leaderboard and trying to update the axios get call every 10 seconds. Using setInterval this is achieved however how do you replace the output rather than repeating the output. https://codepen.io/zepzia/pen/YzPMLLK?editors=1010
<ol id="list"></ol>
const apiOne = 'https://jsonplaceholder.typicode.com/posts';
const list = document.querySelector('#list');
const apiCall = () => {
axios.get(apiOne)
.then(resp => {
resp.data.forEach(item => {
let output = `<li class="item">${item.title} - ${item.id}</li>`;
list.innerHTML += output;
})
})
}
apiCall();
setInterval(() => apiCall(), 10000)

After getting response from your API you need to clear list by calling:
list.innerHTML = '';
You can check also other answers in this thread - How do I clear the content of a div using JavaScript?
Updated codepen

Related

React, component not re-rendering after change in an array state (not the same as others)

I'm trying to make a page that gets picture from a server and once all pictures are downloaded display them, but for some reason the page doesn't re-render when I update the state.
I've seen the other answers to this question that you have to pass a fresh array to the setImages function and not an updated version of the previous array, I'm doing that but it still doesn't work.
(the interesting thing is that if I put a console.log in an useEffect it does log the text when the array is re-rendered, but the page does not show the updated information)
If anyone can help out would be greatly appreciated!
Here is my code.
export function Profile() {
const user = JSON.parse(window.localStorage.getItem("user"));
const [imgs, setImages] = useState([]);
const [num, setNum] = useState(0);
const [finish, setFinish] = useState(false);
const getImages = async () => {
if (finish) return;
let imgarr = [];
let temp = num;
let filename = "";
let local = false;
while(temp < num+30) {
fetch("/get-my-images?id=" + user.id + "&logged=" + user.loggonToken + "&num=" + temp)
.then(response => {
if(response.status !== 200) {
setFinish(true);
temp = num+30;
local = true;
}
filename = response.headers.get("File-Name");
return response.blob()
})
.then(function(imageBlob) {
if(local) return;
const imageObjectURL = URL.createObjectURL(imageBlob);
imgarr[temp - num] = <img name={filename} alt="shot" className="img" src={imageObjectURL} key={temp} />
temp++;
});
}
setNum(temp)
setImages(prev => [...prev, ...imgarr]);
}
async function handleClick() {
await getImages();
}
return (
<div>
<div className="img-container">
{imgs.map(i => {
return (
i.props.name && <div className="img-card">
<div className="img-tag-container" onClick={(e) => handleView(i.props.name)}>{i}</div>
<div className="img-info">
<h3 className="title" onClick={() => handleView(i.props.name)}>{i.props.name.substr(i.props.name.lastIndexOf("\\")+1)}<span>{i.props.isFlagged ? "Flagged" : ""}</span></h3>
</div>
</div>
)
})}
</div>
<div className="btn-container"><button className="load-btn" disabled={finish} onClick={handleClick}>{imgs.length === 0 ? "Load Images" : "Load More"}</button></div>
</div>
)
}
I think your method of creating the new array is correct. You are passing an updater callback to the useState() updater function which returns a concatenation of the previous images and the new images, which should return a fresh array.
When using collection-based state variables, I highly recommend setting the key property of rendered children. Have you tried assigning a unique key to <div className="img-card">?. It appears that i.props.name is unique enough to work as a key.
Keys are how React associates individual items in a collection to their corresponding rendered DOM elements. They are especially important if you modify that collection. Whenever there's an issue with rendering collections, I always make sure the keys are valid and unique. Even if adding a key doesn't fix your issue, I would still highly recommend keeping it for performance reasons.
It is related to Array characteristics of javascript.
And the reason of the console log is related with console log print moment.
So it should be shown later updated for you.
There are several approaches.
const getImages = async () => {
... ...
setNum(temp)
const newImage = [...prev, ...imgarr];
setImages(prev => newImage);
}
const getImages = async () => {
... ...
setNum(temp)
setImages(prev => JOSN.parse(JSON.object([...prev, ...imgarr]);
}
const getImages = async () => {
... ...
setNum(temp)
setImages(prev => [...prev, ...imgarr].slice(0));
}
Maybe it could work.
Hope it will be helpful for you.
Ok the problem for me was the server was not sending a proper filename header so it was always null so the condition i.props.name was never true... lol sorry for the confusion.
So the moral of this story is, always make sure that it's not something else in your code that causes the bad behavior before starting to look for other solutions...

Reusing variables later as integers/text later

I have tried getting cypress to save a text for later usage but I feel unable to reuse it as a variable
cy.get('.unrd').then(($span) => {
const filteredunread = $span.text()
cy.wrap(filteredunread).as('oldunreadmessage');
})
Codeblock to send a mail, wait and return to the inbox expecting an echo reply
cy.get('.unrd').then(($span) => {
cy.get('#oldunreadmessage') //seen as object
const newunread = $span.text()
expect(newunread).to.eq(cy.get('#oldunreadmessage') +1)
})
This gives me errors such as:
expected '(27)' to equal '[object Object]1'
I have tried to use .as(). However I seem to be unable to properly resolve my old object as a text or integer constant.
The first part is fine, but because of the cy.wrap you need to use should or then on the cy.get('#oldunreadmessage')
cy.get('.unrd').then(($span) => {
const newunread = $span.text();
cy.get('#oldunreadmessage').should('have.text', newunread);
})
or
cy.get('.unrd').then(($span) => {
const newunread = $span.text();
cy.get('#oldunreadmessage').then((oldunread) => {
expect(newunread)...
}
})

How to fetch API in JavaScript?

I have written a javascript to fetch API but it is not working can anyone please see that is there any error in my javascript. I have given some parts of my javascript which I think has error.
MY JAVASCRIPT
const redraw = () => {
resultEl.innerHTML = '';
const paged = pageResponse(results, getPageSize(), getCurrPage());
const contents = document.createElement('div');
contents.innerHTML = paged.map(record => `<div class='latestatus'><p class='copytxt'>${record.status}</p><div> <button class="copystatus btn">Copy</button></div></div>`).join('');
resultEl.append(contents);
};
//Fetch API
const retrieveAllStatus = async function() {
// write your asynchronous fetching here
// here we are making a network call to your api
const response = await fetch('https://goodman456.000webhostapp.com/api.php');
// then converting it to json instead of a readable stream
const data = await response.json();
// finally go over the array and return new object with renamed key
const results = data.map(val => ({val.status}));
return results;
}
Please just once visit the link below. It's my request.
https://goodman456.000webhostapp.com/api.php
I would make your work easy, My friends said that the below section
contents.innerHTML = paged.map(record => `<div class='latestatus'><p class='copytxt'>${record.status}</p><div> <button class="copystatus btn">Copy</button></div></div>`).join('');
resultEl.append(contents);
};
Especially the {$record.status} where I need the JSON data to be placed. My friend also said that there is something wrong in fetching API.
Please I have stucked here for a long time. And thanks in advance for those who answer this question.

Struggling to populate from a pair of API's in Vanilla JavaScript

Working on modifying a project I'm learning from.
The initial project is to create a sort of infinitely scrolling Twitter Clone. Posts were grabbed from https://jsonplaceholder.typicode.com/ api, and I'm trying to add another level by bringing in images from another image placeholder API.
I'm a noob, so I was able to successfully grab data from both API's and populate the DOM. Trouble is, with my current structure, I'm repeating placeholder images as what I'm grabbing from the placeholder api is in 5 object blocks. Could use some help in making sure every post has a different photo. Thanks, total newb here. Wondering if I should just be populating an array of objects and working from there, but maybe there's a shortcut I'm missing?
const postsContainer = document.getElementById("posts-container");
const loading = document.querySelector(".loader");
const filter = document.getElementById("filter");
let limit = 5;
let page = 1;
//Fetch Posts from API
async function getPosts() {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
);
const data = await res.json();
return data;
}
//Fetch Photos from another API
async function getPhoto(photo) {
const res = await fetch(`https://randomuser.me/api`);
const data = await res.json();
photo = data.results[0].picture.thumbnail;
return photo;
}
//Show items in DOM
async function showPosts() {
const posts = await getPosts();
const pic = await getPhoto();
posts.forEach((post) => {
const postEl = document.createElement("div");
postEl.classList.add("post");
postEl.innerHTML = `
<div class="number">
<img class="profile-pic" src="${pic}" alt="user photo" />
</div>
<div class="post-info">
<h2 class="post-title">${post.title}</h2>
<p class="post-body">
${post.body}
</p>
</div>
</div>
`;
postsContainer.appendChild(postEl);
});
}
//Show loader and fetch more posts
function showLoading() {
loading.classList.add("show");
setTimeout(() => {
loading.classList.remove("show");
setTimeout(() => {
page++;
showPosts();
}, 1000);
}, 300);
}
//Show initial posts
showPosts();
window.addEventListener("scroll", () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 5) {
showLoading();
}
});
GitHub Repo: https://github.com/unsubstantiated-Script/infinite-scroller
TIA
Problem solved. Needed to move the pic variable inside my forEach loop. That and async the forEach loop.

Images not populating when using Unsplash API

I am learning how to use fetch APIs and I can't seem to figure out why only 1 image is showing up when using the Unsplash API. I think it has something to do with map, but I'm not sure. Any help our guidance is appreciated.
document.getElementById("search").addEventListener("click", () => {
const searchTerm = document.getElementById("searchBox").value;
console.log(searchTerm);
fetch(
`https://api.unsplash.com/search/photos?client_id=e72d3972ba3ff93da57a4c0be4f0b7323346c136b73794e2a01226216076655b&query=${searchTerm}`
)
.then(response => response.json())
.then(data => {
console.log(data);
console.log(data.results);
let searchResults = data.results
.map(searchResults => {
return (document.getElementById("app").innerHTML = `<img src="${
searchResults.urls.small
}">`);
})
.join("");
});
});
Code Sandbox here: https://codesandbox.io/s/yq918mok29
The default 10 images should appear but only 1 shows up. How can I map through the images and show them on the page?
You're overwriting the element's content in each map iteration, so you only see the last one. Use map to build the markup, then drop it into the document.
Something like this:
.then(data => {
let imagesMarkup = '';
data.results
.map(searchResults => {
return (imagesMarkup += `<img src="${searchResults.urls.small}">`);
}); // note that the join was removed here
document.getElementById("app").innerHTML = imagesMarkup;
});
Demo

Categories

Resources