I'm building a simple memory game just to show functionality.
User inserts a string, I shuffle it and present the split chars on the screen - as stars. (* * * *)
Whenever a user will click a star, it will show the real value of the number.
For now I have a text box for input, I shuffle the chars but I'm not sure what is the best way to use that array and present the string as stars that onclick will flip back to the real char. Thanks for helping!
const section = document.querySelector("section");
function myFunction() {
var input = document.getElementById("searchTxt").value;
const x = document.querySelector("p");
const yourInp = "Your input is: "
x.textContent = yourInp;
document.getElementById("str").innerHTML = input;
const cards = input.split('');
const randomize = () => {
cards.sort(() => Math.random() - 0.5);
return cards;
};
const cardsGenerator = () => {
const cards = randomize();
console.log(cards);
cards.forEach(item => {
console.log(item);
});
}
cardsGenerator();
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Game</title>
</head>
<body>
<h1> Memory Game </h1>
<input name="searchTxt" type="search" maxlength="4" id="searchTxt" class="searchField" value="Word" />
<button onclick="myFunction()">Start Game</button>
<p id="yourstr"> </p>
<p id="str"> </p>
<section></section>
</body>
Maybe you want to check this approach out:
const section = document.querySelector("section");
function myFunction() {
var input = document.getElementById("searchTxt").value;
const x = document.querySelector("p");
const yourInp = "Your input is: " + input;
x.textContent = yourInp;
const cards = input.split('');
const randomize = () => {
cards.sort(() => Math.random() - 0.5);
return cards;
};
const cardsGenerator = () => {
container.innerText = ''; // clear container
const cards = randomize();
cards.forEach(item => {
const d = document.createElement("div"); // create div
d.innerText = '*'; // set text to *
d.onclick = () => { d.innerText = item; } // handle onclick to display real value
container.appendChild(d); // append div as child to container
});
}
cardsGenerator();
}
div.cards {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
padding: 3px;
background: gray;
border-radius: 2px;
font-size: x-large;
}
div.cards > div {
display: flex;
justify-content: center;
align-items: center;
margin: 10px;
padding: 10px;
background: white;
border-radius: 6px;
}
<h1> Memory Game </h1>
<input name="searchTxt" type="search" maxlength="4" id="searchTxt" class="searchField" value="Word" />
<button onclick="myFunction()">Start Game</button>
<p id="yourstr"> </p>
<div class="cards" id="container">
</div>
Related
I am new on JavaScript.I am trying to build a speech to text website using JavaScript. I am facing problems when dealing with audio volumes. Here the volume of audio speech(msg) is changing with values from volumeslider. But there is no actual change of volume in my audio.
Here is my piece of code for volumeslider
volume.addEventListener("input", () => {
const vol = volume.value;
msg.volume = vol; document.querySelector("#volume-label").innerHTML = vol*100;
});
const input = document.getElementById("hidden")
const btn1 = document.getElementById("btn1")
const play = document.getElementById("play")
const pause = document.getElementById("pause");
const resume = document.getElementById("resume");
const restart = document.getElementById("restart");
const volume = document.getElementById("volume")
const reader = btn1.addEventListener("click", function() {
input.click();
})
input.addEventListener("change", (event) => {
let file = input.file
if (typeof e === 'undefined') {
const file = event.target.files[0]
if (file) {
const reader = new FileReader()
reader.readAsText(file)
reader.onload = () => console.log(reader.result)
play.addEventListener("click", function() {
msg = new SpeechSynthesisUtterance(reader.result);
msg.volume = 1;
speechSynthesis.speak(msg)
volume.addEventListener("input", () => {
// Get volume Value from the input
const vol = volume.value;
// Set volume property of the SpeechSynthesisUtterance instance
msg.volume = vol;
// Update the volume label
document.querySelector("#volume-label").innerHTML = vol * 100;
});
})
pause.addEventListener("click", () => {
speechSynthesis.pause();
});
resume.addEventListener("click", () => {
speechSynthesis.resume();
});
restart.addEventListener("click", () => {
speechSynthesis.restart();
});
}
}
})
body {
background-color: aqua;
}
#btn1 {
width: 80%;
height: 100px;
margin-bottom: 200px;
}
.btn2 {
width: 20%;
height: 70px;
}
.flex {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 110px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<title>Page02</title>
<link rel="stylesheet" href="C:\Users\CZ\Downloads\Text To Speech Converter in JavaScript\Pageno03\style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="flex">
<input id="hidden" type="file" hidden="hidden" />
<button id="btn1">Select/Upload .txt Files</button>
<div>
<p class="lead">Volume</p>
<input type="range" min="0" max="1" value="1" step="0.1" id="volume" />
<span id="volume-label" class="ms-2">100</span>
</div>
<button id="play">Play</button>
<button id="pause">Pause</button>
<button id="resume">Resume</button>
<button id="restart">Restart</button>
<br>
</div>
<script src="C:\Users\CZ\Downloads\Text To Speech Converter in JavaScript\Pageno03\script.js"></script>
</body>
</html>
Here is my full code:
I am working on a bookmark "collector" app that allows users save websites urls as a collection. I have created an array collectX in the localstorage to save each collections. However I am trying to edit and update each collections that have created on another HTML page.
How can I do that?
Here is what I have tried so far:
//get form values
// create an object of the form values
//create an empty array
//append object of the form values to the empty array
//display array object values
showCollection();
var getButton = document.getElementById('clickIt');
var collectionTitle = document.getElementById("title");
var collectionDescription = document.getElementById('describe')
getButton.addEventListener('click', function(e){
e.preventDefault()
var collections = {
title: collectionTitle.value,
description: collectionDescription.value,
collectedWebsites:[]
}
let webCollections = localStorage.getItem('collectx');
if(webCollections == null){
var collectionObj = []
alert('storage is empty')
}
else{
collectionObj = JSON.parse(webCollections);
}
collectionObj.push(collections);
localStorage.setItem("collectx", JSON.stringify(collectionObj));
showCollection()
});
function showCollection(){
let webCollections = localStorage.getItem('collectx')
if(webCollections == null){
var collectionObj = []
alert('storage is empty')
}
else{
collectionObj = JSON.parse(webCollections);
}
let html= ''
var demos = document.getElementById('demo');
collectionObj.forEach(function(item, index){
html += `<div class="collects">
Title: ${item.title} <br>
Description: ${item.description} </div>`
})
demos.innerHTML = html
}
body{
background-color: #000;
}
.collects{
width: 150px;
height: 100px;
padding: 10px 5px 10px 5px;
margin-right: 20px;
border-radius: 10px;
display: inline-block;
background-color: #fff;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CollectX</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<form id="forms">
<input id="title" type="text" placeholder="Collection name">
<br>
<br>
<input id="describe" type="text" placeholder="Description">
<button id="clickIt"> Submit </button>
</form>
<div id="demo">
</div>
<script src="/script.js"></script>
</body>
</html>
Here is the link to the JSFiddle: https://jsfiddle.net/c3jgezwr/2/
P.S: I have tried to the method used on this page: https://www.xul.fr/javascript/parameters.php
Please take a look to this example
CSS
body {
background-color: #000;
}
.collects {
min-width: 150px;
min-height: 100px;
padding: 10px 5px 10px 5px;
margin-right: 20px;
border-radius: 10px;
display: inline-block;
background-color: #fff;
overflow: hidden;
}
HTML
<form name="form">
<div>
<input name="title" placeholder="Title" />
</div>
<div>
<input name="describe" placeholder="Describe" />
</div>
<div>
<input name="links" placeholder="Add links separated by coma" />
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
JS
const form = document.forms.form;
form.addEventListener("submit", submitHandler);
function getData() {
return JSON.parse(localStorage.getItem("collectx")) ?? [];
}
function submitHandler(event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
const currentData = getData();
localStorage.setItem("collectx", JSON.stringify([...currentData, data]));
form.reset();
render();
}
function render() {
const collection = getData();
const entries = collection
.map(
({ title, describe, links }) => `
<div class="collects">
<p>Title: ${title}</p>
<p>Describe: ${describe}</p>
<p>Links: ${links && links
.split(",")
.map((link) => `${link}`)
.join("<br />")}
</p>
</div>`
)
.join("");
document.querySelector("#root").innerHTML = `
<div>
${entries}
</div>
`;
}
render();
https://jsfiddle.net/m3ws94zo/2/
The idea is to add a input to enter links separated by coma. In a real solution, you probably will need to validate the urls
My code is in this jsfiddle snippet below. Whenever I press the remove button, it requires 2 clicks to remove the boxes that were originally generated with html. If I have added them, then those boxes work properly with one click. The problem lies with these boxes that are made through the markup.
Link to the code : this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box-container {
display: flex;
}
.box-item {
display: inline-block;
height: 30px;
width: 30px;
background: orangered;
margin: 0 10px;
}
.activated {
background: dodgerblue;
}
</style>
</head>
<body>
<div id="box-container">
<span class="1 box-item"></span>
<span class="2 box-item"></span>
<span class="3 box-item"></span>
</div>
<button id="add">Add</button>
<button id="remove">Remove</button>
<script src="main.js"></script>
</body>
</html>
JS CODE
const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");
function Box(element) {
this.__el = element;
this.activated = true;
}
Box.prototype.init = function() {
this.activateBox();
this.__el.addEventListener("click", this.toggleActivation.bind(this));
};
Box.prototype.logger = function() {
console.log(this);
};
Box.prototype.activateBox = function() {
if (this.activated) {
this.__el.classList.add("activated");
}
};
Box.prototype.deactivateBox = function() {
if (!this.activated) {
this.__el.classList.remove("activated");
}
};
Box.prototype.toggleActivation = function() {
this.__el.classList.toggle("activated");
return (this.activated = !this.activated);
};
let box = [];
for (let i = 0; i < boxItems.length; i++) {
box[i] = new Box(boxItems[i]);
box[i].init();
}
const addBox = function() {
const node = document.createElement("span");
node.classList.add("box-item", "activated");
boxContainer.appendChild(node);
};
function removeBox() {
boxContainer.removeChild(boxContainer.lastChild);
}
addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);
PS: I have checked other 2 questions that have the same title, but they don't solve my issue.
The problem is that your HTML includes text nodes between the .box-items:
<div id="box-container">
<span class="1 box-item"></span>
<span class="2 box-item"></span>
<span class="3 box-item"></span>
</div>
So, when you call
boxContainer.removeChild(boxContainer.lastChild);
If a parent's last child node is a text node, that text node will be selected when you use lastChild. That's not what you want - you don't want to select the text nodes. You only want to remove the <span> elements, so you might remove the last item in the .children instead:
const { children } = boxContainer;
boxContainer.removeChild(children[children.length - 1]);
Or, more elegantly, select the lastElementChild property, thanks to Andre's comment:
boxContainer.removeChild(boxContainer.lastElementChild);
(quite confusingly, the final index of children is not the same thing as the node returned by lastChild)
const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");
function Box(element) {
this.__el = element;
this.activated = true;
}
Box.prototype.init = function() {
this.activateBox();
this.__el.addEventListener("click", this.toggleActivation.bind(this));
};
Box.prototype.logger = function() {
console.log(this);
};
Box.prototype.activateBox = function() {
if (this.activated) {
this.__el.classList.add("activated");
}
};
Box.prototype.deactivateBox = function() {
if (!this.activated) {
this.__el.classList.remove("activated");
}
};
Box.prototype.toggleActivation = function() {
this.__el.classList.toggle("activated");
return (this.activated = !this.activated);
};
let box = [];
for (let i = 0; i < boxItems.length; i++) {
box[i] = new Box(boxItems[i]);
box[i].init();
}
const addBox = function() {
const node = document.createElement("span");
node.classList.add("box-item", "activated");
boxContainer.appendChild(node);
};
function removeBox() {
boxContainer.removeChild(boxContainer.lastElementChild);
}
addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);
.box-container {
display: flex;
}
.box-item {
display: inline-block;
height: 30px;
width: 30px;
background: orangered;
margin: 0 10px;
}
.activated {
background: dodgerblue;
}
<div id="box-container">
<span class="1 box-item"></span>
<span class="2 box-item"></span>
<span class="3 box-item"></span>
</div>
<button id="add">Add</button>
<button id="remove">Remove</button>
Or, you can just change the HTML such that there are no text nodes:
<div id="box-container"><span class="1 box-item"></span><span class="2 box-item"></span><span class="3 box-item"></span></div>
const boxContainer = document.getElementById("box-container");
const boxItems = document.getElementsByClassName("box-item");
const addBtn = document.getElementById("add");
const removeBtn = document.getElementById("remove");
function Box(element) {
this.__el = element;
this.activated = true;
}
Box.prototype.init = function() {
this.activateBox();
this.__el.addEventListener("click", this.toggleActivation.bind(this));
};
Box.prototype.logger = function() {
console.log(this);
};
Box.prototype.activateBox = function() {
if (this.activated) {
this.__el.classList.add("activated");
}
};
Box.prototype.deactivateBox = function() {
if (!this.activated) {
this.__el.classList.remove("activated");
}
};
Box.prototype.toggleActivation = function() {
this.__el.classList.toggle("activated");
return (this.activated = !this.activated);
};
let box = [];
for (let i = 0; i < boxItems.length; i++) {
box[i] = new Box(boxItems[i]);
box[i].init();
}
const addBox = function() {
const node = document.createElement("span");
node.classList.add("box-item", "activated");
boxContainer.appendChild(node);
};
function removeBox() {
boxContainer.removeChild(boxContainer.lastChild);
}
addBtn.addEventListener("click", addBox);
removeBtn.addEventListener("click", removeBox);
.box-container {
display: flex;
}
.box-item {
display: inline-block;
height: 30px;
width: 30px;
background: orangered;
margin: 0 10px;
}
.activated {
background: dodgerblue;
}
<div id="box-container"><span class="1 box-item"></span><span class="2 box-item"></span><span class="3 box-item"></span></div>
<button id="add">Add</button>
<button id="remove">Remove</button>
I'm working on a Wheel of Fortune game where a random word is chosen from an array. I created a function below my game function to detect the key pressed from a list of letters displayed on screen from A-Z. My problem is that I can't get the game to detect the key pressed until the randomWord() function is fired after the playGame() button is pressed. I'm trying to get the letter pressed by the user in the buttonPress() function to match a letter in the wordChoice.length loop and display on the screen where the _ would be and then rule out the letter after it's been used. I tried creating the letterClicked variable and making it global so that my playGame() function can access it but I'm not having any luck matching the letter selected by the user and the letter in the display box above the play button. What am I doing wrong here? I tried console logging throughout the randomWord() function but the keypress is only being detected after you click play and essentially reset the game. Here is my code below. Thanks for your help!
<DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Wheel of Fortune</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>
<body>
<body>
<div id="container">
<div id="header">
<p class="welcome">Welcome to Wheel of Fortune!</p>
<!-- The letters will be tied to the number of letters in the random array -->
<p class="letters">There are <span id="numbers">0</span> letters in this word</p>
<!-- The user will be given a number of choices and with each wrong choice, they lose a turn -->
<p class="lives">You have <span id="guesses">0</span> guesses left</p>
<span id="words"></span><br>
<button id="play" onclick="playGame()">Play</button>
</div>
<div id="alphabet" onclick="buttonPress(event)">
<button>A</button>
<button>B</button>
<button>C</button>
<button>D</button>
<button>E</button>
<button>F</button>
<button>G</button>
<button>H</button>
<button>I</button>
<button>J</button>
<button>K</button>
<button>L</button>
<button>M</button>
<br>
<button>N</button>
<button>O</button>
<button>P</button>
<button>Q</button>
<button>R</button>
<button>S</button>
<button>T</button>
<button>U</button>
<button>V</button>
<button>W</button>
<button>X</button>
<button>Y</button>
<button>Z</button>
</div>
<span id="your-guess">You guessed </span>
</div>
<script src="main.js"></script>
</body>
</html>
body {
margin: 0 auto;
width: 1000px;
font-size: 20px;
background: url("http://res.cloudinary.com/angelrodriguez/image/upload/c_crop,h_624/v1534810805/wheeloffortune.jpg");
background-size: cover;
color: white;
}
#header {
margin: 20px;
}
#alphabet {
margin: 20px;
}
button {
border: 2px solid blue;
font-size: 20px;
}
#words {
font-size: 30px;
margin: 10px;
letter-spacing: 20px;
}
#play {
margin: 20px;
}
// 3. Quit the game if the player wants to.
// 5. Keep track of letters the player has guessed.
// 6. Show the player their progress.
// 7. Finish when the player has guessed the word.
// Create global variables
let gameOver = false;
var guessesLeft = 6;
var letterClicked;
var wordArray = ["JAVASCRIPT", "ARRAYS", "FUNCTIONS", "HOISTING", "RECURSION", "EVENTS", "KEYUP", "TERNARY"];
// 1. Pick a random word.
//Start a new game
function playGame() {
newGame.addEventListener("click", function() {
//fire the randomWord function to generate a new word
randomWord();
})
}
// Pass the letter event from buttonPress into the randomWord function
function randomWord(letter) {
var answerList = [];
// console.log(answerList);
// letterGuessed = "";
console.log(letterClicked);
var wordChoice = wordArray[Math.floor(Math.random() * wordArray.length)];tbw
var wordSplit = wordChoice.split('');
// console.log(wordSplit);
for (var i = 0; i < wordSplit.length; i++) {
answerList[i] = "_";
}
// if the letter is in the word
// Update the players progress with the guess
for (var z = 0; z < wordChoice.length; z++) {
if (wordChoice[z] === letterClicked) {
letterClicked = answerList[i];
// answerList[i].innerHTML = letterGuessed;
}
}
//Display underscores on page representing each word in the random word
wordDisplay.innerHTML = answerList;
//Display number of letters in the random word on the page
var remainingLetters = wordChoice.length;
letterCount.innerHTML = "The word is " + remainingLetters +
" letters long";
}
// 2. Take the player’s guess.
function buttonPress(e) {
letterClicked = e.target.textContent;
document.getElementById("your-guess").innerHTML = "You guessed the letter " + letterClicked;
//fix issue with clicking divs
}
// If the player wants to quite the game {
// Quit the game
// }
// Grab elements
var numbers = document.querySelector("#numbers");
var guesses = document.querySelector("#guesses");
var wordDisplay = document.querySelector("#words");
var letterCount = document.querySelector(".letters");
var newGame = document.querySelector("#play");
var letterBoxes = document.querySelector("#alphabet");
To get a letter in buttonPress you are able to use e.toElement.textContent.
I did some solution, but it's not a great example, i think.
let words = [ "TERNARY"], guessesLeft, chosenWord;
let getRandomWord = words => {
return words[Math.floor(Math.random()*words.length)];
}, updateGuesses = count => {
guesses.innerText = count;
guessesLeft = count;
}, updateWords = word => {
document.getElementById('words').innerHTML = word;
}, hideAlphabet = () => alphabet.style.display = 'none',
setGameStatus = status => document.getElementById("status").innerHTML = status;
play.addEventListener('click', e => {
e.target.style.display = 'none'; // hide when game started.
alphabet.style.display = 'block';
chosenWord = getRandomWord(words);
updateGuesses(chosenWord.length);
updateWords(String("*").repeat(chosenWord.length))
});
alphabet.addEventListener('click', e => {
let letter = e.toElement.textContent;
e.toElement.disabled = true;
if (!new RegExp(letter).test(chosenWord)) {
updateGuesses(guessesLeft -1);
} else {
let newString = document.getElementById('words').innerHTML.split(''), indexesOfALetter = [];
for(let i = 0; i < chosenWord.length; i += 1) // here for is a fastest way.
if (chosenWord[i] === letter) indexesOfALetter.push(i);
indexesOfALetter.forEach(i => newString[i] = letter);
updateWords(newString.join(''));
}
if (!/\*/.test(document.getElementById('words').innerHTML)) {
hideAlphabet();
setGameStatus("Congratulations! You won that game");
}
if (guessesLeft < 1) {
hideAlphabet();
setGameStatus("Unfortunately, you lost the game ;(");
updateWords(chosenWord);
}
});
body {
margin: 0 auto;
width: 1000px;
font-size: 20px;
color: black;
}
#header {
margin: 20px;
}
#alphabet {
display: none;
margin: 20px;
}
button {
border: 2px solid blue;
font-size: 20px;
}
#words {
font-size: 30px;
margin: 10px;
letter-spacing: 20px;
}
#play {
margin: 20px;
}
<div id="container">
<div id="header">
<p class="welcome">Welcome to Wheel of Fortune!</p>
<!-- The user will be given a number of choices and with each wrong choice, they lose a turn -->
<p class="lives">You have <span id="guesses">0</span> guesses left</p>
<span id="words"></span><br>
<button id="play">Play</button>
</div>
<div id="alphabet">
<button>A</button>
<button>B</button>
<button>C</button>
<button>D</button>
<button>E</button>
<button>F</button>
<button>G</button>
<button>H</button>
<button>I</button>
<button>J</button>
<button>K</button>
<button>L</button>
<button>M</button>
<br>
<button>N</button>
<button>O</button>
<button>P</button>
<button>Q</button>
<button>R</button>
<button>S</button>
<button>T</button>
<button>U</button>
<button>V</button>
<button>W</button>
<button>X</button>
<button>Y</button>
<button>Z</button>
</div>
<span id="status"></span>
</div>
I am learning javascript and practicing by making a simple book list app.
I wanted to add the books to local storage. But the array I want to push the values into is starting as undefined and then it is set to null. And the if else statement is not working it runs through both the if statement despite the fact that the condition should return true. It starts on line 32 First a variable booklist is declared then it checks to see if bookLists exists in local storage if it does not it sets the value bookLists to a empty array ELSE it grabs booklist from local storage and parses the array adds the book to the book list. Then sets the item to local storage. At least that is what I was trying to do. Any ideas what I am not doing correctly? 0.0
The HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">
<link rel="stylesheet" href="css/main.css">
<style>
.correct {
color: antiquewhite;
padding: 7px;
margin: 5px 0px 16px 0px;
border: 3px forestgreen solid;
border-radius: 6px;
background-color: forestgreen;
}
.error {
color: antiquewhite;
padding: 7px;
margin: 5px 0px 16px 0px;
border: 3px firebrick solid;
border-radius: 6px;
background-color: firebrick;
}
</style>
<title>Book List Generator</title>
</head>
<body>
<div id="container" class="container booklistContainer">
<h1 class="booklistH1">Add a Book to the Booklist &:<)</h1>
<form id="form">
<div>
<label for="title">Title</label>
<input type="text" id="title" class="u-full-width">
</div>
<div>
<label for="author">Author</label>
<input type="text" id="author" class="u-full-width">
</div>
<div>
<label for="isbn">ISBN#</label>
<input type="text" id="isbn" class="u-full-width">
</div>
<div>
<button class="u-full-width" id="submit">Add a bookmark</button>
</div>
<hr>
<table class="u-full-width">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>ISBN</th>
<th></th>
</tr>
</thead>
<tbody id="BookListBody"></tbody>
</table>
</div>
<script src="Js/booklistGenerator.js"></script>
</body>
</html>
The Css
.booklistH1 {
letter-spacing: 1px;
margin: 3rem 0rem;
font-size: 1.5rem;
}
.booklistContainer {
margin-bottom: 7rem;
}
#media screen and (max-width: 519px) {
.booklistH1 {
letter-spacing: 1px;
margin: 3rem 0rem;
font-size: 1rem;
}
}
#media screen and (max-width: 352px) {
.booklistH1 {
font-size: 0.9rem;
}
}
#media screen and (max-width: 352px) {
.booklistH1 {
letter-spacing: 1px;
margin: 3rem 0rem;
font-size: 0.8rem;
}
}
The Javascript
// adding a event listener
const sub = document.getElementById("submit").addEventListener("click", valuerRetrivel);
const removeBook = document.getElementById("BookListBody").addEventListener("click", bookRemover);
// the book constructer
function BookConstructer (title, author, isbn){
this.title = title;
this.author = author;
this.isbn = isbn;
};
// The Ui constructer
function UiConstructor() {}
// adding a method to the Ui constructer prtotype
UiConstructor.prototype.addBookToList = function(book){
// grab the table body
const list = document.getElementById("BookListBody");
//create the table row to append the table cells
const row = document.createElement("tr");
// add the cells to the table row using templet strings
row.innerHTML = `
<td>${book.title}</td>
<td>${book.author}</td>
<td>${book.isbn}</td>
<td>X</td>
`;
// append to the table body
list.appendChild(row);
let bookList;
if (localStorage.getItem("bookList" === null)) {
bookList = [];
}else {
bookList = JSON.parse(localStorage.getItem("bookList"));
}
bookList.push(book);
localStorage.setItem("bookList", JSON.stringify(bookList));
alert("task saved");
}
UiConstructor.prototype.alertMessage = function(message, className) {
// create and append the alert message
const alertDiv = document.createElement("div");
alertDiv.className = `alert ${className}`;
alertDiv.setAttribute("id", "alert");
const alertDivTextNode = document.createTextNode(message);
alertDiv.appendChild(alertDivTextNode);
const parent = document.getElementById("container");
const form = document.getElementById("form");
parent.insertBefore(alertDiv, form);
// remove the alert after 3 seconds
setTimeout(function(){
document.getElementById("alert").remove();
},3000);
}
UiConstructor.prototype.successMessage = function(message, className) {
// create and append the success message
const successDiv = document.createElement("div");
successDiv.className = `success ${className}`;
successDiv.setAttribute("id", "success");
const successtDivTextNode = document.createTextNode(message);
successDiv.appendChild(successtDivTextNode);
const parent = document.getElementById("container");
const form = document.getElementById("form");
parent.insertBefore(successDiv, form);
console.log(UiConstructor);
// remove the alert after 3 seconds
setTimeout(function(){
document.getElementById("success").remove();
},3000);
}
// retriving the form values
function valuerRetrivel(e) {
// initating a Ui constructor to accses its methods
const ui = new UiConstructor();
// reguler expression that checks for whitespace
const regexp = /^\s+$/;
// retriving the form input values
const title = document.getElementById("title").value,
author = document.getElementById("author").value,
isbn = document.getElementById("isbn").value;
const resultTitle = regexp.test(title);
const resultAuthor = regexp.test(author)
const resultIsbn = regexp.test(isbn);
// cheacking for white space
if (resultTitle === true
|| resultAuthor === true
|| resultIsbn === true
|| title === ""
|| author === ""
|| isbn === "") {
// calling the alert message and passing the arguments
ui.alertMessage("All form fields must have content", "error");
e.preventDefault();
return false;
}else {
// calling the book constructer function to create a book object
const book = new BookConstructer(title, author, isbn);
// initating the ui constructer and creating a new book object
ui.addBookToList(book);
console.log(ui);
// calling the success message method and passing the arguments
ui.successMessage("Success!", "correct");
// clearing the current input values
const titleClear = document.getElementById("title").value = "",
authorClear = document.getElementById("author").value = "",
isbnClear = document.getElementById("isbn").value = "";
e.preventDefault();
return true;
}
};
function bookRemover(e) {
if (e.target.className === "delete") {
if(confirm("Are you sure you want to delete this link?")) {
e.target.parentElement.parentElement.remove();
e.preventDefault();
}
}
}
You have a typo
if (localStorage.getItem("bookList" === null)) {
which is always false.
This causes the bookList to never be instantiated from the true clause, and also as a result the storage item is attempted to be used, which is where the null parse comes in from
JSON.parse(localStorage.getItem("bookList"))