Cannot read properties of undefined (Inside a Constructor) - javascript

I'm building a library app from The Odin Project, and this error occurs when I try to change read status for Not Read read using a click event.
the error occurs on line 88, reading status value. How can I fix that?
thank you.
console.log(
"What is the toggle initial value?...",
myLibrary[parseInt(retrieveBookToToggle)].status
);
let myLibrary = [];
const btnAdd = document.querySelector("btn-add");
//Object Constructor
class Book {
constructor(title, author, pages, status) {
this.title = title;
this.author = author;
this.pages = pages;
this.status = status;
}
//Add a new book to array
function addBookToLibrary(title, author, pages, status) {
let book = new Book(title, author, pages, status);
myLibrary.push(book);
displayBooksOnPage()
}
//Display array to card
function displayBooksOnPage() {
const books = document.querySelector(".books-container");
//remove displayed cards before loop array
const removeDivs = document.querySelectorAll(".card");
console.log("Show me the node count of the current card divs........", removeDivs);
for (let i = 0; i < removeDivs.length; i++) {
removeDivs[i].remove();
}
//Loop Library array and display to the cards
let index = 0;
myLibrary.forEach(myLibrarys => {
const card = document.createElement("div");
card.classList.add("card");
books.appendChild(card);
//remove book button
const removeBookButton = document.createElement("button");
removeBookButton.classList.add("remove-book-button");
removeBookButton.textContent = "Remove Book";
console.log("show me my currentnarray objects inside of foreach........", myLibrary);
//link data attribute of the remove button to the array and card
removeBookButton.dataset.linkedArray = index;
index++;
console.log("show me dataset link back to the array...", removeBookButton.dataset.linkedArray);
card.appendChild(removeBookButton);
//start event listener/remove array item from array and card from parent div via data link
removeBookButton.addEventListener("click", removeBookFromLibrary);
function removeBookFromLibrary() {
let retrieveBookToRemove = removeBookButton.dataset.linkedArray;
console.log("attempting to remove array item via data attribute...", parseInt(retrieveBookToRemove));
myLibrary.splice(parseInt(retrieveBookToRemove), 1);
card.remove();
displayBooksOnPage;
}
const readStatusButton = document.createElement("button");
readStatusButton.classList.add("read-status-button");
readStatusButton.textContent = "Change Status";
readStatusButton.dataset.linkedArray = index;
console.log("show dataset link back to the array for read status button", readStatusButton.dataset.linkedArray);
card.appendChild(readStatusButton);
readStatusButton.addEventListener("click", toggleReadStatus);
function toggleReadStatus() {
let retrieveBookToToggle = readStatusButton.dataset.linkedArray;
Book.prototype = Object.create(Book.prototype);
const toggleBook = new Book();
console.log("what's the toggle initial value? ", myLibrary[parseInt(retrieveBookToToggle)].status);
if (myLibrary[parseInt(retrieveBookToToggle)].status == "Read") {
toggleBook.status = "Not Read";
myLibrary[parseInt(retrieveBookToToggle)].status = toggleBook.status;
} else if (myLibrary[parseInt(retrieveBookToToggle)].status == "Not Read") {
toggleBook.status = "Read";
myLibrary[parseInt(retrieveBookToToggle)].status = toggleBook.status;
}
displayBooksOnPage();
}
for (let key in myLibrarys) {
const para = document.createElement("p");
para.textContent = (`${myLibrarys[key]}`);
card.appendChild(para);
}
})
}
const addBookButton = document.querySelector(".btn-add");
addBookButton.addEventListener("click", displayTheForm);
function displayTheForm() {
document.getElementById("books-form").style.display = "";
}
const submitButton = document.querySelector(".btn-add");
submitButton.addEventListener("click", intakeFormData);
function intakeFormData() {
let Title = document.getElementById("title").value;
let Author = document.getElementById("author").value;
let Pages = document.getElementById("pages").value;
let Status = document.getElementById("status").value;
if ((Title == "") || (Author == "") || (Pages == "") || (Status == "")) {
return;
}
addBookToLibrary(Title, Author, Pages, Status);
document.getElementById("add-book").reset();
}
const clearButton = document.getElementById("btn-reset");
clearButton.addEventListener("click", clearForm());
function clearForm() {
document.getElementById("add-book").reset();
}

Related

How do i show an image via input while a certain object is selected ( nft card/image previewer )

How do I use file input to load a picture, store the picture in cookies, or some other to store te picture that doesn't use an alternate language, and only show said picture when a particular object (nft card) is being displayed. The program is basically an image slider that shows information along with a picture pertaining to the current selected nft card.
const prevbtn = document.querySelector("#prev-btn");
const nextbtn = document.querySelector("#next-btn");
let cardName = document.querySelector("#name");
let cardDescription = document.querySelector("#description");
let cardPrice = document.querySelector(".eth");
let cardTime = document.querySelector("#time2");
let cardCreator = document.querySelector("span");
let deck = [];
let card;
let formSubmit = document.querySelector(".formsubmit");
let formName = document.querySelector("#form-name");
let formDescription = document.querySelector("#description2");
let formPrice = document.querySelector("#form-price");
let formTime = document.querySelector("#time-left");
let formCreator = document.querySelector("#creator-name");
let formNFTart = document.querySelector("#nft-art")
let selectedFile;
let picShow = document.getElementById("newimagetoggle");
let picChange = document.querySelector(".nft-card-image")
let newElement = document.createElement("input");
newElement.setAttribute("type", "file");
newElement.setAttribute("accept", "image/*");
//NFT Card Class creator
class NFTcard {
constructor(id, name, description, price, time, creator, image) {
this.id = id
this.name = name
this.description = description
this.price = price
this.time = time
this.creator = creator
this.imageID = image
}
};
// set starting card
let currentCard = 0
// create deck to store nft Card creations
deck = [];
// Create new NFT and change NFT Image from user input
let createNewNFT = function () {
// new image
selectedFile = newElement.files[0]
let reader = new FileReader();
reader.addEventListener("load", function () {
// convert image file to base64 string
picChange.src = reader.result;
}, false);
if (selectedFile) {
reader.readAsDataURL(selectedFile);
}
// retrieve user nft data and place in new nft card object
let newNftName = formName.value
newNftName = new NFTcard(`${deck.length}`, `${formName.value}`, `${formDescription.value}`, `${formPrice.value}eth`, `${formTime.value}`, `${formCreator.value}`, `${deck.length}`);
deck.push(newNftName);
// clear input fields
formName.value = ""
formDescription.value = ""
formPrice.value = ""
formTime.value = ""
formCreator.value = ""
}
picShow.addEventListener('click', function () {
newElement.click();
});
formSubmit.onclick = function () {
createNewNFT();
};
// Switch to current card
let switchCard = function () {
card = deck[currentCard];
cardName.textContent = card.name;
cardDescription.textContent = card.description;
cardPrice.textContent = card.price;
cardTime.textContent = card.time;
cardCreator.textContent = card.creator;
picChange.src = card.imageID
}
// load initial card
window.addEventListener("DOMContentLoaded", function () {
switchCard(currentCard);
});
//Next button switch card
nextbtn.addEventListener('click', function () {
currentCard++;
if (currentCard > deck.length - 1) {
currentCard = 0
};
switchCard(currentCard);
})
//Prev button switch card
prevbtn.addEventListener('click', function () {
currentCard--;
if (currentCard < 0) {
currentCard = deck.length - 1;
}
switchCard(currentCard)
})```

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

Keep Todo Results after browser refreshing

I created a todo app to add and remove tasks on the page.
however i would like to keep todo results when browser refreshed .
Is that possible to make this like storing data on db or any storage to save these results?
any idea to make this to save data ??
Now I posted the complete code hereee! because i cant posted code here before
let menu = document.querySelector(".bs");
let btn1 = document.querySelector(".btn");
let btn2 = document.querySelector(".btn3");
let irp = document.querySelector(".date");
let inp = document.querySelector(".input");
let bsd = document.querySelector(".sss");
let brs = document.querySelector(".marker");
let addBr = () => {
btn1.addEventListener("click", addBr);
let br = document.createElement("DIV");
let dd = document.createElement("H1");
dd.innerHTML = (inp.value);
br.className = "red";
var bn = document.createElement("H1");
bn.innerHTML = (irp.value);
menu.appendChild(br);
br.appendChild(dd);
br.appendChild(bn);
if( inp.value == "") {
br.remove();
}
else {
menu.appendChild(br);
}
if( irp.value == "") {
dd.innerHTML = "Albenis";
}
else {
menu.appendChild(br);
}
let ttt = document.createElement("BUTTON");
ttt.className = "marker";
ttt.innerHTML = "Remove";
br.appendChild(ttt);
// This is the important change. Part of creating the .ttt element
// is setting up its event listeners!
ttt.addEventListener('click', () => br.remove());
};
btn1.addEventListener("click", addBr);
// Call `addBr` once to add the initial element
addBr();
<html>
<body>
<div class="bs">
<input type="text" class="input">
<input type="date" class="date">
<button class="btn">
Add
</button>
</div>
</body>
</html>
TL;DR: use localStorage to read the items at page load and write the items when they change, like in the final version
To keep your todo entries, you need to store it in a Database. This can be either a local database in the website like localStorage. Or you need to build a backend which is connected to a Database and send and load the Data from there.
localStorage example:
const items = [{ name: "My Todo" }, { name: "My Todo 2" }];
const setItems = () => {
localStorage.setItem("items", JSON.stringify(items));
};
const getItems = () => {
return JSON.parse(localStorage.getItem("items"));
};
Including your code:
const getItems = () => {
return JSON.parse(localStorage.getItem("items"));
};
const items = getItems() || [];
const setItems = () => {
localStorage.setItem("items", JSON.stringify(items));
};
let addBr = (item) => {
let br = document.createElement("DIV");
let dd = document.createElement("H1");
dd.innerHTML = (item ? item.name : inp.value);
br.className = "red";
var bn = document.createElement("H1");
bn.innerHTML = (item ? item.name : irp.value);
if (!item) {
items.push({ name: inp.value });
setItems();
}
menu.appendChild(br);
br.appendChild(dd);
br.appendChild(bn);
if( inp.value == "") {
br.remove();
}
else {
menu.appendChild(br);
}
if( irp.value == "") {
dd.innerHTML = "Albenis";
}
else {
menu.appendChild(br);
}
let ttt = document.createElement("BUTTON");
ttt.className = "marker";
ttt.innerHTML = "Remove";
br.appendChild(ttt);
// This is the important change. Part of creating the .ttt element
// is setting up its event listeners!
ttt.addEventListener('click', () => br.remove());
};
for (const item of items) {
addBr(item);
}
btn1.addEventListener("click", () => addBr());

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