(index):19 Uncaught ReferenceError: Search is not defined at HTMLInputElement.onkeyup - javascript

i'm making an app with marvel's api and in this app i'm trying to put a search bar but i'm not getting it.
Every time I try to search for a name in this api the function Search() it is undefined in the html.
I don't understand how the function is not defined in the html.
What can i do to change this ?
const timeStamp = "1622146184";
const privateKey = "somekey";
const publicKey = "someotherkey";
const md5 = "b34f17bceca201652c24e9aa21777da9";
const Hero = document.querySelector('article');
const input = document.getElementById('myInput');
fetch(`http://gateway.marvel.com/v1/public/characters?ts=${timeStamp}&apikey=${publicKey}&hash=${md5}&limit=6`).then((response)=> {
return response.json();
}).then((jsonParsed)=>{
jsonParsed.data.results.forEach(element => {
const srcImage = element.thumbnail.path + '.' + element.thumbnail.extension;
const nameHero = element.name;
createHero(srcImage, nameHero, Hero);
},
function Search() {
// Declare variables
const filter = input.value.toUpperCase();
const textName2 = nameHero;
// Loop through all textName2st items, and hide those who don't match the search query
for (i = 0; i <= textName2.length; i++) {
const p = textName2[i].getElementsByTagName("p")[0];
txtValue = p.textContent || p.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
textName2[i].style.display = "";
} else {
textName2[i].style.display = "none";
}
}
})
console.log(jsonParsed);
})
function createHero(srcImage, nameHero, divToAppend){
const divPai = document.createElement('section');
const textName = document.createElement('p');
const img = document.createElement('img');
textName.textContent = nameHero;
img.src= srcImage;
divPai.appendChild(img);
divPai.appendChild(textName);
divToAppend.appendChild(divPai);
divPai.classList.add("personagem");
}
<main>
<input type="text" id="myInput" onkeyup="Search()" placeholder="Search for names.." />
<article id="herois"></article>
</main>

The search function is undefined because the fetch isn't closed properly. I'm also guessing that you only want to make a request when the user has actually entered some search query. I don't see multiple article elements so don't really know what to do with this. But do note that in this case you might as well use getElementById. And if there are multiple articles with the same id that it won't work.
const timeStamp = "1622146184";
const privateKey = "somekey";
const publicKey = "someotherkey";
const md5 = "b34f17bceca201652c24e9aa21777da9";
const Hero = document.getElementById('herois');
const input = document.getElementById('myInput');
async function Search() {
console.log(input.value);
await fetch(`http://gateway.marvel.com/v1/public/characters?ts=${timeStamp}&apikey=${publicKey}&hash=${md5}&limit=6`)
.then( response => {
return response.json();
})
.then(jsonParsed => {
console.log(jsonParsed);
jsonParsed.data.results.forEach(element => {
const srcImage = element.thumbnail.path + '.' + element.thumbnail.extension;
const nameHero = element.name;
createHero(srcImage, nameHero, Hero);
});
});
// Declare variables
const filter = input.value.toUpperCase();
const textName2 = nameHero;
// Loop through all textName2st items, and hide those who don't match the search query
for (i = 0; i <= textName2.length; i++) {
const p = textName2[i].getElementsByTagName("p")[0];
txtValue = p.textContent || p.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
textName2[i].style.display = "";
} else {
textName2[i].style.display = "none";
}
}
}
function createHero(srcImage, nameHero, divToAppend){
const divPai = document.createElement('section');
const textName = document.createElement('p');
const img = document.createElement('img');
textName.textContent = nameHero;
img.src= srcImage;
divPai.appendChild(img);
divPai.appendChild(textName);
divToAppend.appendChild(divPai);
divPai.classList.add("personagem");
}
<main>
<input type="text" id="myInput" onchange="Search()" placeholder="Search for names.." />
<article id="herois"></article>
</main>

Related

querySelectorAll with variable doesn't select the element

I want to select all elements using querySelectorAll with variable "amountClass" but NodeList always is empty
function addingCoin() {
const table = document.querySelector('.list__table');
table.addEventListener('submit', (event) => {
event.preventDefault();
const walletCryptos = document.querySelector('#usersCrypto');
const coinAmount = event.target.inputAmount;
const coinRow = coinAmount.parentElement.parentElement.parentElement;
const coinName = coinRow.querySelector('.name').textContent;
const coinPrice = coinRow.querySelector('.price').textContent.match(/\d+(\.\d+)?/)[0];
const coinValue = coinAmount.value*coinRow.querySelector('.price').textContent.match(/\d+(\.\d+)?/)[0];
let amountClass = coinName;
let existingCoin = document.querySelectorAll(amountClass);
if (existingCoin.length > 0) {
existingCoin[0].innerText = coinAmount.value +
existingCoin[0].value;
} else {
const newTr = document.createElement("tr");
const nameTh = document.createElement("th");
const priceTh = document.createElement("th");
const amountTh = document.createElement("th");
const valueTh = document.createElement("th");
nameTh.innerText = coinName;
if (coinPrice < 0.95) {
priceTh.innerText = parseFloat(coinPrice).toFixed(8);
} else {
priceTh.innerText = parseFloat(coinPrice).toFixed(2);
};
amountTh.innerText = coinAmount.value;
amountTh.className += coinName;
if (coinValue < 0.95) {
valueTh.innerText = parseFloat(coinValue).toFixed(8);
} else {
valueTh.innerText = parseFloat(coinValue).toFixed(2);
};
walletCryptos.appendChild(newTr);
walletCryptos.appendChild(nameTh);
walletCryptos.appendChild(priceTh);
walletCryptos.appendChild(amountTh);
walletCryptos.appendChild(valueTh);
}});
};
I think the problem may be with this part of code:
let existingCoin = document.querySelectorAll(amountClass);
What can i change to make this work properly? Is there any other solution to check does the element with the certain class exist?
You need a . at the beginning to select a class.
Trim the text content in case it has whitespace around the text.
const coinName = coinRow.querySelector('.name').textContent.trim();
let amountClass = '.' + coinName
Finally I have found the solution:
const amountClass = '.' + coinName;
const existingCoin = document.querySelectorAll(amountClass.replace(/ /g,''));

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

Javascript - can't iterate over object in incremental search

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);
};

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 issue

I'm trying to use local storage so that my invites stay on the page when refreshed. How would I go about implementing this into my code. I really don't know where to start and I'm really struggling with it. Please cans someone just show me how to implement this into my code. Ive been creating child elements and appending them to the UL in the HTML.
const form = document.getElementById("registrar");
const input = form.querySelector("input");
const mainDiv = document.querySelector(".main");
const ul = document.getElementById("invitedList");
const div = document.createElement('div');
const filterLabel = document.createElement('label');
const filterCheckBox = document.createElement('input');
filterLabel.textContent = "Hide those who havent responded";
filterCheckBox.type = 'checkbox';
div.appendChild(filterLabel);
div.appendChild(filterCheckBox);
mainDiv.insertBefore(div, ul);
/*
This creates a checkbox to see you has confirmed if they are coming
to the event or not.
*/
filterCheckBox.addEventListener("change", (e) => {
const isChecked = e.target.checked;
const lis = ul.children;
if (isChecked) {
for (let i = 0; i < lis.length; i += 1) {
let li = lis[i]
if (li.className === 'responded') {
li.style.display = '';
} else {
li.style.display = 'none';
}
}
} else {
for (let i = 0; i < lis.length; i += 1) {
let li = lis[i]
li.style.display = '';
}
}
});
/*
This function creates new list items (the invites).
*/
createLi = (text) => {
createElement = (elementName, property, value) => {
const element = document.createElement(elementName);
element[property] = value;
return element;
}
appendElement = (elementName, property, value) => {
const element = createElement(elementName, property, value);
li.appendChild(element);
return element;
}
const li = document.createElement("li");
appendElement("span", "textContent", text);
appendElement("label", "textContent", "Confirmed")
.appendChild(createElement("input", "type", "checkbox"));
appendElement("button", "textContent", "edit");
appendElement("button", "textContent", "remove");
return li;
}
}
form.addEventListener("submit", (event) => {
event.preventDefault();
const text = input.value;
input.value = "";
const li = createLi(text);
ul.appendChild(li);
});
ul.addEventListener("change", () => {
const checkbox = event.target;
const checked = checkbox.checked;
const listItem = checkbox.parentNode.parentNode;
if (checked) {
listItem.className = "responded";
} else {
listItem.className = "";
}
});
ul.addEventListener("click", (e) => {
if (e.target.tagName === 'BUTTON') {
const button = e.target;
const li = button.parentNode;
const ul = li.parentNode;
const action = button.textContent;
const nameActions = {
remove: () => {
ul.removeChild(li);
},
edit: () => {
const span = li.firstElementChild;
const input = document.createElement('input');
input.type = 'text';
input.value = span.textContent;
li.insertBefore(input, span);
li.removeChild(span);
button.textContent = 'Save';
},
Save: () => {
const input = li.firstElementChild;
const span = document.createElement('span');
span.textContent = input.value;
li.insertBefore(span, input);
li.removeChild(input);
button.textContent = 'edit';
}
};
nameActions[action]();
}
});
I only can give you an idea for this, if you are planning to save any big data to localStorage, you can save your data to string and remake it to JSON object!
Here's an exmaple for saving data set
var toSave = [ ];
var whatToSave = (Your invites data List, maybe a "text" var for your code?, organize
to array or loop for your "UL" tag)
for(var i=0;i<whatToSave.length;i++){
var obj = [];
obj[i] = {
text:whatToSave[i].text,
data1:whatToSave[i].data1,
data2:whatToSave[i].data2,
...
}
toSave.push(obj[i]);
}
var saveToString = JSON.stringify(toSave);
localStorage.setItem('invites', saveToString); //your invite data saved in local
storage
....
//after refreshing or when you need to use your saved data
var cameBack = JSON.parse(localStorage.getItem('invites'));
//this will return same data again
//and make function to make UL using retured data array
you don't really need to for loop and push if you already organized needed data to array, just wrote it to make you understand an idea to save data in localStorage. I don't know if this will help you but get an idea and implement it to your project :)

Categories