Javascript - can't iterate over object in incremental search - javascript

I'm very new to javascript/dev so I hope there is a an obvious solution that I've not thought of. My code returns search items from TVMaze.com API. The feature giving me trouble is the incremental search (as a user types in input box, the code returns and displays images by creating a new div and appending images, removing and replacing the an div).
My problem is that on deleting all characters from input box, I receive the error: "Uncaught (in promise) TypeError: shows is not iterable" which I suppose means that there is no object to iterate over? Thanks in advance for any help.
const input = document.querySelector("#query");
input.addEventListener("input", async function (e) {
e.preventDefault();
const searchTerm = e.target.value;
const config = { params: { q: searchTerm } };
const res = await axios.get(`http://api.tvmaze.com/search/shows?`, config);
makeImages(res.data);
clearList();
});
const makeImages = (shows) => {
const div = document.createElement("div");
for (let result of shows) {
if (result.show.image) {
const img = document.createElement("IMG");
img.className += "resultImage";
img.src = result.show.image.medium;
const title = document.createElement("h3");
title.className += "resultTitle";
title.innerText = result.show.name;
const year = document.createElement("h4");
year.className += "score";
year.innerText = result.show.premiered;
var sub = year.innerText.substring(0, 4);
var yearNum = parseInt(sub);
div.append(year);
div.append(img);
div.append(title);
document.body.appendChild(div);
}
if (yearNum <= 2000) {
var retro = document.createElement("h5");
retro.className = "retro";
retro.innerText = "retro";
div.append(retro);
}
}
};
let clearList = () => {
var allImg = document.querySelectorAll("IMG");
if (allImg.length === 0) {
document.createElement("div");
return makeImages();
}
var oldDiv = document.querySelector("div");
oldDiv.remove();
console.log(oldDiv);
};

Related

Having trouble reducing the total in this small todo app

I am having a hard time trying to figure out how to get the the value from every new Li and reduce it (add) to then output to my h2. Can't figure out what I am doing wrong. Any help would be greatly appreciated! Codepen: https://codepen.io/Chasehud26/pen/Poagjwy
I tried to console.log different variables to see if there were any hints of what is going wrong.
const form = document.querySelector("form")
const nameInput = document.querySelector("#name-input")
const priceInput = document.querySelector("#price-input")
const button = document.querySelector("button")
const nameUl = document.querySelector("#item-name")
const priceUl = document.querySelector("#item-price")
const h2 = document.querySelector("h2")
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
form.addEventListener("submit", function (e) {
e.preventDefault()
let nameVal = nameInput.value
let priceVal = priceInput.value
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
nameUl.appendChild(nameLi)
nameLi.innerHTML = nameInput.value
priceUl.appendChild(priceLi)
priceLi.textContent = `${priceInput.value}`
showTotals()
})
//TRYING TO ADD TOGETHER ALL THE PRICE VALUES AND THEN PUT IT TO MY H2//
function showTotals() {
const priceList = document.querySelectorAll("li")
for (let priceLists of priceList) {
const total = []
total.push(parseFloat(priceLists.textContent));
const totalMoney = total.reduce(function (total, item) {
total += item;
return total;
}, 0);
const finalMoney = totalMoney.toFixed(2);
h2.textContent = finalMoney;
}
}
You need to have your const total [] array initialized outside of the for loop. also, when you setup your <li> decorators, you need to differentiate between the number and non-number fields, since the way you had it, it was trying to add the text 'li' fields also:
/// truncated for clarity
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
priceLi.classList.add('num') // <== this line added
//// =================
function showTotals() {
const priceList = document.querySelectorAll("li.num") // added class
const total = [] // <== move this to here
for (let priceLists of priceList) {
total.push(parseFloat(priceLists.textContent));
const totalMoney = total.reduce(function (total, item) {
total += item;
return total;
}, 0);
const finalMoney = totalMoney.toFixed(2);
h2.textContent = finalMoney;
}

The values are not replacing with new values

firstly, when I search for any city it shows the weather correctly, but when I try to search for another city/country It shows the details of the same city that I have searched for before. I think there is something wrong with my JavaScript code. I think the new values that I'm fetching from the API are not getting replaced by the old values.
let enterCity = document.querySelector("#enterCity");
let city = document.querySelector(".city");
let country = document.querySelector(".country");
let temp = document.querySelector(".temp");
let text = document.querySelector(".text");
let inputVal = enterCity.value;
// the base url
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2****************`;
fetch(url).then((response) => {
return response.json();
}).then((data) => {
let search = document.querySelector(".search");
search.addEventListener("click", () => {
let container = document.querySelector(".container");
card = document.createElement("div");
card.className = "card";
city = document.createElement("h2");
city.className = "city";
***The problems are with the innerText down below ***
city.innerText = data.location.name;
country = document.createElement("h5");
country.className = "country";
country.innerText = data.location.country;
temp = document.createElement("h4");
temp.className = "temp";
temp.innerText = data.current.temp_c;
span1 = document.createElement("span");
span1.id = "deg";
span1.innerText = "°C"
temp.appendChild(span1);
icon = document.createElement("img");
icon.className = "icon";
icon.src = data.current.condition.icon;
text = document.createElement("h3");
text.className = "text";
text.innerText = data.current.condition.text;
card.appendChild(city);
card.appendChild(country);
card.appendChild(temp);
card.appendChild(icon);
card.appendChild(text);
container.appendChild(card);
Here, I have also cleared the input value
that I'm taking from the user
enterCity.value = "";
});
});
let search = document.querySelector(".search");
search.addEventListener("click", () => {
let enterCity = document.querySelector("#enterCity");
let city = document.querySelector(".city");
let country = document.querySelector(".country");
let temp = document.querySelector(".temp");
let text = document.querySelector(".text");
var inputVal = enterCity.value;
// the base url
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2********************`;
fetch(url).then((response) => {
return response.json();
}).then((data) => {
//Do the remaining works here
})
});
The actual problem was already assigned the value of document.querySelector("#enterCity"); when the page loads instead of on click. So value of enterCity was not changing when you click the search button.
Note : If the key you given in the question is your personal API key,
then please try to change it in the console, because it is not good
idea to publish it in the outside.
This is happening beacause you haven't added onchange event listener on your input(enter city).if you don't add onchange event this will take only your inital value.
So add a onchange listener then call fetch api inside of it.
Dummy example -
let entercity=document.querySelector("#entercity");
entercity.addEventListener('change',()=>{
let inputVal=entercity.value;
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2476da35134140211107`;
fetch(url).then((res)=>console.log(res))
.catch((err)=>console.log(err));
})

Incorrect loading order from local storage

I'm having problem with loading from local storage.
Here's a part of the code
const getTerminus = () => {
let terminus;
if (localStorage.getItem("terminus") === null) {
terminus = [];
} else {
terminus = JSON.parse(localStorage.getItem("terminus"));
}
let directions;
if (localStorage.getItem("directions") === null) {
directions = [];
} else {
directions = JSON.parse(localStorage.getItem("directions"));
}
terminus.forEach(async(stop) => {
let API_URL =
"https://ckan.multimediagdansk.pl/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/d3e96eb6-25ad-4d6c-8651-b1eb39155945/download/stopsingdansk.json";
let response = await fetch(API_URL);
let data = await response.json();
const {
stops,
stopId,
stopName,
stopCode,
zoneId
} = data;
let input = stop;
let ID;
let dataArr = [];
for (let i = 0; i < stops.length; i++) {
if (
stops[i].stopName === input &&
stops[i].stopCode === directions[terminus.indexOf(input)] &&
stops[i].zoneId === 1
) {
ID = stops[i].stopId;
dataArr = [ID, stops[i].stopName];
}
}
API_URL = `https://ckan2.multimediagdansk.pl/delays?stopId=${ID}`;
response = await fetch(API_URL);
data = await response.json();
const {
delay,
estimatedTime,
routeId,
headsign
} = data;
let times = [];
let routeIds = [];
let headsigns = [];
for (let i = 0; i < delay.length; i++) {
times.push(delay[i].estimatedTime);
routeIds.push(delay[i].routeId);
headsigns.push(delay[i].headsign);
}
routeIds.push(" ");
times.push(" ");
const cardDiv = document.createElement("div");
cardDiv.classList.add("card");
const stopNameDiv = document.createElement("div");
stopNameDiv.classList.add("stop-name-div");
cardDiv.appendChild(stopNameDiv);
const stopNameSpan = document.createElement("span");
stopNameSpan.innerText = dataArr[1];
stopNameSpan.classList.add("stop-name-span");
stopNameDiv.appendChild(stopNameSpan);
const scheduleDiv = document.createElement("div");
scheduleDiv.classList.add("schedule-div");
cardDiv.appendChild(scheduleDiv);
if (headsigns.length !== 0) {
routeIds.unshift("Line");
headsigns.unshift("Direction");
times.unshift("Departure");
}
const lineSpan = document.createElement("span");
lineSpan.innerText = routeIds.join("\n");
lineSpan.classList.add("line-span");
scheduleDiv.appendChild(lineSpan);
const dirSpan = document.createElement("span");
dirSpan.innerText = headsigns.join("\n");
dirSpan.classList.add("dir-span");
scheduleDiv.appendChild(dirSpan);
const timeSpan = document.createElement("span");
timeSpan.innerText = times.join("\n");
timeSpan.classList.add("time-span");
scheduleDiv.appendChild(timeSpan);
const buttonsDiv = document.createElement("div");
buttonsDiv.classList.add("buttons-div");
cardDiv.appendChild(buttonsDiv);
const deleteButton = document.createElement("button");
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.classList.add("delete-button");
buttonsDiv.appendChild(deleteButton);
const dirButton = document.createElement("button");
dirButton.innerHTML = '<i class="fas fa-retweet"></i>';
dirButton.classList.add("reverse-button");
buttonsDiv.appendChild(dirButton);
stopList.appendChild(cardDiv);
});
};
document.addEventListener("DOMContentLoaded", getTerminus);
Terminus contains stop names, and directions contains direction codes.
On refresh, it fetches data from API based on stop name and direction, and displays a card with departure time etc.
The problem is, on closing and re-opening the page cards are sometimes displayed in a wrong order. I have found out, that as time between closing and opening lengthens, the probability of this occurring gets higher. After simple refresh everything is in correct order.
Does it have something to do with browser cache? Has anyone had similar issue or knows what's going on?
Alright, as #Yoshi stated, it was insequential promise error. I managed to fix it by using reduce().
Here are the threads that helped me
Resolve promises one after another (i.e. in sequence)?
Why Using reduce() to Sequentially Resolve Promises Works

How do I Convert a HTML Collection into an array, without emptying it? #2

I am trying to convert an HTML Collection of "li"s into an array, but the result in the array being emptied.
I read this question and applied that, but it doesn't work.How do I convert a HTMLCollection into an array, without emptying it?
<body>
<ul id="base"></ul>
<script>
const json = [{
"id" : "1",
"date" : "2013/05/05",
},{
"id" : "2",
"date" : "2019/05/05",
}];
for (item of json) {
const list = document.createElement('li');
list.textContent = `${item.date}`;
base.appendChild(list)
}
///the code above works fine.
const base = document.getElementById("base");
const myNodeList = base.getElementsByTagName("li");
console.log(myNodeList);
// gives HTMLCollection
const myArray = Array.from(myNodeList)
// returns empty array
</script>
</body>
the result
I tested the same code on console and it worked fine as below.
The code cannot work before you are using base before initializing it. Placing the initialization before using it makes it work.
Here I modified it: https://jsfiddle.net/tk78z5gq/
Thank you so much guys!
The problem was async.
I should have said that earlier, I fetch the data from NeDB with async function.
The array was empty because DOM was executed before async function fetching data was executed.
The full code below was fixed one. I'm not sure this is best way, but at least it worked.
let dataM = null;
async function getHTMLData() {
const response = await fetch('/api');
const data = await response.json();
dataM = data;
const base = document.getElementById("base");
for (item of data) {
const root = document.createElement('li');
root.className = "col-md-auto";
root.title = `${item.date}`;
const border = document.createElement('div');
border.className = "row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative";
root.appendChild(border);
const flex = document.createElement('div');
flex.className = "col p-4 d-flex flex-column position-static";
border.appendChild(flex);
const country = document.createElement('strong');
country.className = "d-inline-block mb-2 text-primary";
const title = document.createElement('h3');
title.className = "mb-0";
const date = document.createElement('div');
date.className = "mb-1 text-muted";
date.id = "date";
const fieldItem = document.createElement('p');
fieldItem.className = "mb-auto";
const imageRoot = document.createElement('figure');
imageRoot.className = "image mb-2";
const link = document.createElement('a');
link.className = "p-4";
const linkText = document.createTextNode("Source");
country.textContent = `${item.country}`;
title.textContent = `${item.title}`;
date.textContent = `${item.date}`;
fieldItem.textContent = `${(item.fieldItem)}`;
for (var i = 0; i < item.imageSrc.length; i++) {
const image = document.createElement('img');
image.src = item.imageSrc[i];
image.alt = 'seized items'
image.className = "w-5 h-5";
// image.crossOrigin ="use-credentials";
imageRoot.appendChild(image);
}
const imageText = document.createElement('text');
imageText.innerHTML = `<br>${item.imageText}`;
imageRoot.appendChild(imageText);
link.appendChild(linkText);
link.title = "Source";
link.href = item.URL;
link.className = "";
flex.append(country, title, date, fieldItem, imageRoot, link);
base.appendChild(root);
}
}
sortDate();
async function sortDate() {
const gethtml = await getHTMLData();
const base = await document.getElementById("base");
const myNodeList = await base.getElementsByTagName("li");
const myArray = Array.from(myNodeList);
myArray.sort(function (a, b) {
return new Date(a.title) > new Date(b.title)? -1
: new Date(a.title) < new Date(b.title)? 1
: 0;
})
for (i = 0; i < myArray.length; i++) {
base.appendChild(base.removeChild(myArray[i]))}
}
index.js
app.get('/api', (request, response) => {
database.find({}).exec(function(err, data){
if (err) {
response.end();
return;
}
response.json(data);
})
});

Local Storage not loading upon return visit?

I'm making a browser game but I've run into a issue I cant fix no matter how hard I try.
Click the green square increases the counter
and console shows variable being saved to localStorage
but upon returning on the website it returns to 0
Below is my entire JS file. Only part that matters is at the bottom and you can go see for yourself at https://sleepyshepherd.com
//Saved Variables
let ashCount = 0;
let firetruck = 0;
//Initialize Game
window.onload = function() {
const realmTab = document.createElement("div");
const settingsTab = document.createElement("div");
const shopTab = document.createElement("div");
const statsTab = document.createElement("div");
const upgradesTab = document.createElement("div");
const burningBtn = document.createElement("div");
const enslavedTab = document.createElement("div");
const e1 = document.createElement("div");
realmTab.id = "realm";
upgradesTab.id = "upgrades";
settingsTab.id = "settings";
shopTab.id = "shop";
statsTab.id = "stats";
enslavedTab.id = "enslaved";
burningBtn.id = "burning";
e1.id = "e1";
const t1 = document.createTextNode("Realm");
realmTab.appendChild(t1); 
const t2 = document.createTextNode("Upgrades");
upgradesTab.appendChild(t2); 
const t3 = document.createTextNode("Shop");
shopTab.appendChild(t3); 
const t4 = document.createTextNode("Stats");
statsTab.appendChild(t4); 
const t5 = document.createTextNode("Settings");
settingsTab.appendChild(t5); 
document.getElementById("menu").appendChild(realmTab);
document.getElementById("menu").appendChild(upgradesTab);
document.getElementById("menu").appendChild(shopTab);
document.getElementById("menu").appendChild(statsTab);
document.getElementById("menu").appendChild(settingsTab);
document.getElementById("destroy").appendChild(burningBtn);
document.getElementById("destroy").appendChild(enslavedTab);
document.getElementById("enslaved").appendChild(e1);
//Menu Buttons
const viewport1 = document.querySelector(".viewport");
//Realm View Select
document.querySelector("#realm").addEventListener("click",  function() {
viewport1.id = "realmView";
});
//Upgrades View Select
document.querySelector("#upgrades").addEventListener("click",  function() {
viewport1.id = "upgradeView";
});
//shop View Select
document.querySelector("#shop").addEventListener("click",  function() {
viewport1.id = "shopView";
});
//stats View Select
document.querySelector("#stats").addEventListener("click",  function() {
viewport1.id = "statsView";
});
//settings View Select
document.querySelector("#settings").addEventListener("click",  function() {
viewport1.id = "settingsView";
});
// Destroy
function increaseAsh() {
ashCount += 1;
}
document.querySelector("#destroy").addEventListener("click", increaseAsh);
//Resources
const r1 = document.createElement("div");
r1.id = "r1";
document.querySelector("#resources").appendChild(r1);
const t6 = document.createElement("p");
r1.appendChild(t6);
window.setInterval(function() {
t6.textContent = ashCount;
}, 16);
//load game
let sg = JSON.parse(localStorage.getItem("save"));
sg.ashCount = ashCount;
}
// Save Game Interval
window.setInterval(function() {
let save = {
ashCount: ashCount,
firetruck: firetruck
}
localStorage.setItem("save", JSON.stringify(save));
}, 10000);
you wrote sg.ashCount = ashCount; when you want ashCount = sg.ashCount;
add a console.log(sg);

Categories