I have to create a basic Movie listing site wherein i can add or remove a movie from favorites. Instead of the add to favourite button , I want to add the heart icon from bootstrap. Also the rating of the film (star icons) under each film name.
// DUMMY names
var names = {
1: {
name: "Red Notice",
desc: "An Interpol agent tracks the world's most wanted art thief.",
img: "rn.jpg",
},
2: {
name: "Dune",
desc: "the son of a noble family entrusted with the protection of the most valuable asset and most vital element in the galaxy.",
img: "dune.jpg",
},
3: {
name: " Escape Room",
desc: "Six people unwillingly find themselves locked in another series of escape rooms, slowly uncovering what they have in common to survive..",
img: "esc.jpg",
},
4: {
name: "Antim: The Final Truth",
desc: "The cop played by Salman fights the land mafia in the film. ",
img: "4.jpg",
},
5: {
name: "Dhamaka",
desc: "Reassigned from TV to radio, a frustrated anchor sees both danger and opportunity when he receives threatening calls on the air. ",
img: "5.jpg",
}
};
var movie = {
// (A) PROPERTIES
hPdt: null, // HTML names list
hItems: null, // HTML current movie
items: {}, // Current items in movie
// (B) LOCALSTORAGE movie
// (B1) SAVE CURRENT movie INTO LOCALSTORAGE
save: function() {
localStorage.setItem("movie", JSON.stringify(movie.items));
},
// (B2) LOAD movie FROM LOCALSTORAGE
load: function() {
movie.items = localStorage.getItem("movie");
if (movie.items == null) { movie.items = {}; } else { movie.items = JSON.parse(movie.items); }
},
// (B3) EMPTY ENTIRE movie
nuke: function() {
if (confirm("Empty favourite List?")) {
movie.items = {};
localStorage.removeItem("movie");
movie.list();
}
},
// (C) INITIALIZE
init: function() {
// (C1) GET HTML ELEMENTS
movie.hPdt = document.getElementById("movie-names");
movie.hItems = document.getElementById("movie-items");
// (C2) DRAW names LIST
movie.hPdt.innerHTML = "";
let p, item, part;
for (let id in names) {
// WRAPPER
p = names[id];
item = document.createElement("div");
item.className = "p-item";
movie.hPdt.appendChild(item);
// PRODUCT IMAGE
part = document.createElement("img");
part.src = "img/" + p.img;
part.className = "p-img";
item.appendChild(part);
// PRODUCT NAME
part = document.createElement("div");
part.innerHTML = p.name;
part.className = "p-name";
item.appendChild(part);
// PRODUCT DESCRIPTION
part = document.createElement("div");
part.innerHTML = p.desc;
part.className = "p-desc";
item.appendChild(part);
// ADD TO fav
part = document.createElement("input");
part.type = "button";
part.value = "Add to Favorites";
part.className = "movie p-add";
part.onclick = movie.add;
part.dataset.id = id;
item.appendChild(part);
}
// (C3) LOAD movie FROM PREVIOUS SESSION
movie.load();
// (C4) LIST CURRENT movie
movie.list();
},
// (D) LIST CURRENT movie ITEMS (IN HTML)
list: function() {
// (D1) RESET
movie.hItems.innerHTML = "";
let item, part, pdt;
let empty = true;
for (let key in movie.items) {
if (movie.items.hasOwnProperty(key)) { empty = false; break; }
}
// (D2) movie IS EMPTY
if (empty) {
item = document.createElement("div");
item.innerHTML = "List is empty";
movie.hItems.appendChild(item);
} else {
let p, total = 0,
subtotal = 0;
for (let id in movie.items) {
// ITEM
p = names[id];
item = document.createElement("div");
item.className = "c-item";
movie.hItems.appendChild(item);
// NAME
part = document.createElement("div");
part.innerHTML = p.name;
part.className = "c-name";
item.appendChild(part);
// REMOVE
part = document.createElement("input");
part.type = "button";
part.value = "X";
part.dataset.id = id;
part.className = "c-del movie";
part.addEventListener("click", movie.remove);
item.appendChild(part);
}
// EMPTY BUTTONS
item = document.createElement("input");
item.type = "button";
item.value = "Remove all from Favorites";
item.addEventListener("click", movie.nuke);
item.className = "c-empty movie";
movie.hItems.appendChild(item);
}
},
// (E) ADD ITEM INTO movie
add: function() {
if (movie.items[this.dataset.id] == undefined) {
movie.items[this.dataset.id] = 1;
} else {
movie.items[this.dataset.id]++;
}
movie.save();
movie.list();
},
// (G) REMOVE ITEM FROM movie
remove: function() {
delete movie.items[this.dataset.id];
movie.save();
movie.list();
},
};
window.addEventListener("DOMContentLoaded", movie.init);
body {
background-color: rgb(210, 241, 223);
}
.title {
text-align: center;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
padding-bottom: 20px;
}
#movie-wrap {
font-family: arial, sans-serif;
display: grid;
grid-template-columns: 80% 20%;
margin: 0 auto;
max-width: 4000px;
}
input.movie,
button.movie {
font-weight: bold;
font-size: 1em;
padding: 10px;
border: none;
color: rgb(58, 56, 158);
background: #929cf5;
cursor: pointer;
}
.name {
text-align: center;
}
/* (B) names LIST */
#movie-names {
display: grid;
grid-template-columns: auto auto;
grid-gap: 30px;
padding: 10px;
}
.p-item {
padding: 10px;
border: 1px solid #aaa;
text-align: center;
}
.p-name {
text-transform: uppercase;
font-weight: bold;
font-size: 1.1em;
}
.p-img {
max-width: 180px;
}
.p-desc {
color: #777;
font-size: 0.9em;
line-height: 1.5em;
}
input.p-add {
width: 80%;
}
/* (D) CURRENT SHOPPING movie */
#movie-items {
padding: 10px;
background: #d8cbcb;
margin: 10px;
}
.c-item {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
}
.c-name {
width: 80%;
font-size: 1.3em;
line-height: 1.5em;
}
.c-del {
width: 20%;
}
input.c-empty {
width: 100%;
margin-top: 10px;
}
/* (E) RESPONSIVE */
#media (max-width: 768px) {
#movie-wrap {
grid-template-columns: 60% 40%;
}
#movie-names {
grid-template-columns: auto;
}
}
<!DOCTYPE html>
<html>
<head>
<title>MOVIE LISTING WEBSITE</title>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<h1 class="title">Movie Listing App</h1>
<div id="movie-wrap">
<div class="name">
<h2>Movie Names</h2>
<div id="movie-names">
</div>
</div>
<div class="name">
<h2>Favorites</h2>
<div id="movie-items">
</div>
</div>
</div>
</body>
</html>
Also I would like to know if there is a less complicated method to do make this site. Any help would be appreciated.
ps: I dont know why the code is showing error here. It runs properly on my pc
see: https://www.tutorialrepublic.com/twitter-bootstrap-tutorial/bootstrap-icons.php
you first need to import bootstrap to your header in your html page:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.5.0/font/bootstrap-icons.css">
and then you can use icons like this:
<span class="bi-star"></span>
Related
So, my parent container is quiz-container, the child of that is #quiz, the child of that is. slide. The quiz/slide needs to be absolute, or the Q/A will shuffle its way down the page as the next question button is clicked.
The quiz-container should automatically adjust its height based on the size of the #quiz or. slide question/answer so it appears correctly on the phone and so you don't need to scroll forever to click the next button. The button already moves relative to the height of the quiz-container, so that's what I want.
I tried to set a height in px then have it adjust itself with an
overflow: hidden;
but that didn't work.
<style type="text/css">
body {
font-size: 20px;
font-family: 'Work Sans', sans-serif;
color: #333;
font-weight: 300;
text-align: center;
background-color: #f8f6f0;
}
h1 {
font-weight: 300;
margin: 0px;
padding: 10px;
font-size: 20px;
background-color: #444;
color: #fff;
}
.section-description {
margin-bottom: 20px;
}
.question {
position: relative;
font-size: 30px;
margin-bottom: 10px;
}
.answers {
position: relative;
margin-bottom: 20px;
text-align: left;
display: inline-block;
}
.answers label {
display: block;
margin-bottom: 10px;
}
button {
position: absolute;
font-family: 'Work Sans', sans-serif;
font-size: 22px;
background-color: #279;
color: #fff;
border: 0px;
border-radius: 3px;
padding: 20px;
cursor: pointer;
margin-top: 30px;
margin-bottom: 0px;
z-index: 100;
clear: both;
display: block;
bottom: calc(0px + (100% - var(--slide-height)));
left: 60%;
transform: translateX(-10%);
}
button:hover {
background-color: #38a;
}
.slide {
position: absolute;
height: auto;
left: 0px;
top: 0px;
width: 100%;
z-index: 1;
opacity: 0;
transition: opacity 0.5s;
border: 5px purple solid;
}
.active-slide {
opacity: 1;
z-index: 2;
}
.quiz-container {
position: relative;
height: 600px;
overflow: hidden;
display: flex;
border: 5px red solid;
}
.previous {
/* styles for the second button */
position: absolute;
left: 30%; /* aligns element horizontally to center of parent */
transform: translateX(-10%); /* moves element to left by 50% of its own width */
bottom: calc(0px + (100% - var(--slide-height)));
}
#quiz > .slide {
position: absoluate;
height: min-content;
overflow: hidden;
border: 5px solid blue;
}
</style>
<h1>QUIZ</h1>
<div class="quiz-container">
<div id="quiz">
</div>
</div>
<div class="block"><button class="previous" id="previous" type="button">Previous Question</button><button id="next" type="button">Next Question</button><button id="submit" type="button">Submit Quiz</button></div>
<div id="results"> </div>
<div id="results"> </div>
<div id="category-scores"> </div>
<div id="raw-scores"> </div>
<script>
// variable for categories
const resultsContainer = document.getElementById('results');
const categoryScoresContainer = document.getElementById('category-scores');
const rawScoresContainer = document.getElementById('raw-scores');
const quizContainer = document.getElementById("quiz");
const submitButton = document.getElementById("submit");
(function() {
// Functions
function buildQuiz() {
// variable to store the HTML output
const output = [];
// for each question...
myQuestions.forEach((currentQuestion, questionNumber) => {
// variable to store the list of possible answers
const answers = [];
// and for each available answer...
for (letter in currentQuestion.answers) {
// ...add an HTML radio button
answers.push(
`<label id="quiz-container">
<input id="answers" type="radio" name="question${questionNumber}" value="${letter}">
${letter} :
${currentQuestion.answers[letter]}
</label>`
);
}
// add this question and its answers to the output
output.push(
`<div id="quiz-container" class="slide">
${currentQuestion.description ? `<div class="section-description">${currentQuestion.description}</div>` : ''}
<div class="question"> ${currentQuestion.question} </div>
<div class="answers"> ${answers.join("")} </div>
</div>`
);
});
// combine output list into one string of HTML and put it on the page
quizContainer.innerHTML = output.join("");
const nextButton = document.getElementById("next");
nextButton.addEventListener("click", function() {
const description = document.getElementById("description");
if (description) quizContainer.removeChild(description);
});
}
function showResults() {
// gather answer containers from our quiz
const answerContainers = quizContainer.querySelectorAll('.answers');
// keep track of user's answers
let numCorrect = 0;
// for each question...
myQuestions.forEach((currentQuestion, questionNumber) => {
// find selected answer
const answerContainer = answerContainers[questionNumber];
const selector = `input[name=question${questionNumber}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
// if answer is correct
if (userAnswer === currentQuestion.correctAnswer) {
// add to the number of correct answers
numCorrect++;
scores[currentQuestion.category]++;
//multiplies by 2 for final result
scores[currentQuestion.category]++;
}
});
//hide myQuestions
quizContainer.innerHTML = "";
// show number of correct answers out of total
resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;
categoryScoresContainer.innerHTML = `
<p>Word Knowledge = ${scores.wk/2} out of 18</p>
<p>Arithmetic Reasoning = ${scores.ar/2} out of 15</p>
<p>Paragraph Comprehension = ${scores.pc/2} out of 8</p>
<p>Mathmematics Knowledge = ${scores.mk/2} out of 13</p>`;
// hide previous, next and submit button, and make quiz read-only
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const submitButton = document.getElementById("submit");
previousButton.style.display = "none";
nextButton.style.display = "none";
submitButton.style.display = "none";
const inputElements = quizContainer.querySelectorAll("input");
inputElements.forEach(input => {
input.setAttribute("disabled", true);
});
//add restart button
const restartButton = document.getElementById("restart");
restartButton.style.display = "block";
restartButton.addEventListener("click", function() {
location.reload();
});
}
function showSlide(n) {
slides[currentSlide].classList.remove('active-slide');
slides[n].classList.add('active-slide');
currentSlide = n;
if (currentSlide === 0) {
previousButton.style.display = 'none';
} else {
previousButton.style.display = 'inline-block';
}
if (currentSlide === slides.length - 1) {
nextButton.style.display = 'none';
submitButton.style.display = 'inline-block';
} else {
nextButton.style.display = 'inline-block';
submitButton.style.display = 'none';
}
}
function showNextSlide() {
showSlide(currentSlide + 1);
}
function showPreviousSlide() {
showSlide(currentSlide - 1);
}
// Variables
const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');
const myQuestions = [{
category: "wk",
description: "<h2>PART I - WORD KNOWLEDGE. YOU WILL HAVE 7 MINUTES TO COMPLETE.</h2><br /><h4>THIS TEST HAS QUESTIONS ABOUT THE MEANING OF WORDS. EACH QUESTION HAS AN UNDERLINED WORD. YOU ARE TO DECIDE WHICH OF THE FOUR POSSIBLE ANSWERS MOST NEARLY MEANS THE SAME AS THE UNDERLINED WORD. THEN WRITE THE ANSWER ON THE APPROPRIATE SPACE ON YOUR ANSWER SHEET.</h4>",
question: "1. <b><u>SMALL</u></b> MOST NEARLY MEANS?",
answers: {
a: "STURDY",
b: "ROUND",
c: "CHEAP",
d: "LITTLE"
},
correctAnswer: "d"
},
{
category: "ar",
description: "<h2>PART II - ARITHMETIC REASONING - YOU WILL HAVE FOURTEEN (14) MINUTES:</h2><h4>THIS IS A TEST OF YOUR ABILITY TO SOLVE ARITHMETIC PROBLEMS. USE YOUR SCRATCH PAPER FOR ANY FIGURING YOU NEED TO DO.</h4>",
question: "1. TWO AUTOMOBILES START TOGETHER FROM THE SAME PLACE AND TRAVEL ALONG THE SAME ROUTE. THE FIRST AVERAGES 40 MPH. THE SECOND 55 MPH. HOW MANY MILES FURTHER ALONG THE ROUTE IS THE SECOND AUTO AT THE END OF THE 5TH HOUR?",
answers: {
a: "55 x 5",
b: "55 - 40",
c: "(55x5) - (40x5)",
d: "55/5 - 40/5"
},
correctAnswer: "c"
},
{
category: "pc",
description: "<h2>PART III - PARAGRAPH COMPREHENSION - YOU WILL HAVE SEVEN (7) MINUTES:</h2>",
question: "1. THE DUTY OF THE LIGHTHOUSE KEEPER IS TO KEEP THE LIGHT BURNING NO MATTER WHAT HAPPENS, SO THAT SHIPS WILL BE WARNED OF THE PRESENCE OF DANGEROUS ROCKS. IF A SHIPWRECK SHOULD OCCUR NEAR THE LIGHTHOUSE, EVEN THOUGH HE WOULD LIKE TO AID IN THE RESCUE OF IT'S CREW AND PASSENGERS, THE LIGHTHOUSE KEEPER MUST......",
answers: {
a: "STAY AT HIS LIGHT",
b: "RUSH TO THEIR AID",
c: "TURN OUT THE LIGHT",
d: "QUICKLY SOUND THE SIREN"
},
correctAnswer: "a"
},
{
category: "mk",
description: "<h2>PART IV - MATHEMATICS KNOWLEDGE - YOU WILL HAVE TWELVE (12) MINUTES:</h2>",
question: "1. WHICH OF THE FOLLOWING IS THE SMALLEST PRIME NUMBER GREATER THAN 200?",
answers: {
a: "201",
b: "205",
c: "211",
d: "214"
},
correctAnswer: "c"
},
];
// Kick things off
buildQuiz();
// Pagination
const previousButton = document.getElementById("previous");
const nextButton = document.getElementById("next");
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
let scores = {
wk: 0,
ar: 0,
pc: 0,
mk: 0,
};
// Show the first slide
showSlide(currentSlide);
// Event listeners
submitButton.addEventListener('click', showResults);
previousButton.addEventListener("click", showPreviousSlide);
nextButton.addEventListener("click", showNextSlide);
})();
</script>
I am trying to remove a note from local storage by identifying its
title. I checked w3schools and this forum for info. I am able to save
the array but, I can't remove a specific note.
I tried, no change, an example of what I am trying to achieve,
This is my local storage before removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}, {title: "Read", content: "Go to the library"}] 0: {title:
"Laundry", content: "Fold Clothes"} 1: {title: "Cook", content: "Buy
Food"} 2: {title: "Read", content: "Go to the library"}
My desired output after removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}] 0: {title: "Laundry", content: "Fold Clothes"} 1: {title:
"Cook", content: "Buy Food"}
I want to be able to remove an item based on its title Read
const editNote = (e) => {
saveContent.addEventListener('click', (e) => {
e.preventDefault()
let notes = []
let note = {
title: noteTitle.value,
content: noteContent.value
}
// Parse the serialized data back into an aray of objects
notes = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
notes.push(note);
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(notes));
// input.textContent = note.title
//remove notes by id
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
}
}
delNote.addEventListener('click', (e) => {
removeNote()
e.preventDefault()
// window.location.href='index.html'
})
})
}
editNote()
You need to set item into local storage after you update your data
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
localStorage.setItem('items', JSON.stringify(notes))
}
}
localStorage.removeItem('ITEM TO REMOVE');
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
I eventually figured it out. Thank you all for replying and providing guidelines.
let input = document.querySelector('.input-bar')
let addItem = document.querySelector('.submit-btn')
let clearAll = document.querySelector('.clear-btn')
// pay attension to indentation and ele location it will determine success
addItem.addEventListener('click', (e) => {
e.preventDefault()
// Parse the serialized data back into an aray of objects
items = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
items.push(input.value);
item = input.value
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(items));
var clear = document.createElement('button')
clear.innerHTML= '<i class="fa fa-trash" style="font-size:20px ;color: #ac2412"></i>'
let itemsEl = document.getElementById('items')
let para = document.createElement("P");
var t = document.createTextNode(`${input.value}`);
para.appendChild(t);
para.appendChild(clear)
itemsEl.appendChild(para);
input.value = ''
clear.addEventListener('click', (e) => {
itemsEl.removeChild(para)
e.preventDefault()
for (let index = 0; index < items.length; index++) {
if (items[index] === para.textContent) {
items.splice(index, 1)
localStorage.setItem('items', JSON.stringify(items));
}
}
})
})
clearAll.addEventListener('click', (e) => {
document.getElementById('items').innerHTML = ''
localStorage.clear()
})
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
color: white;
background-color: black;
margin: 40px 0px;
text-align: center;
}
input {
width: 300px;
height: 46px;
outline: none;
background: transparent;
border-color: silver;
border-radius: 0;
color: var(--mainWhite);
font-size: 1.7rem;
}
h1 {
margin: 20px 0px;
}
.submit-btn {
margin: 0px 5px;
width: 50px;
height: 50px;
outline: none;
/* color: white; */
background-color: rgb(21, 96, 194);
color: white;
font-size: 1.7rem;
}
.items-list {
list-style-type: none;
}
li {
display: inline-flex;
border: 1px solid slategrey;
font-size: 22px;
margin: 20px 0px 0px 0px;
}
button {
outline: none;
margin: 0px 0px 0px 200px;
}
.clear-btn {
width: 100px;
height: 40px;
margin: 30px;
outline: none;
background-color: rgb(21, 96, 194);
color: white;
font-size: 20px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<title>Groceries</title>
</head>
<body>
<h1>Grocery List</h1>
<div>
<input class="input-bar" type="text">
<span>
<button class="submit-btn">
<i class="fa fa-pencil" aria-hidden="true"></i>
</button>
</span>
<ul class="items-list" id="items"></ul>
</div>
<button class="clear-btn">Clear</button>
<script src="index.js"></script>
</body>
</html>
I'm trying to make a Single Page Application with pure JavaScript (no additional frameworks or libraries). The problem is that the values I add to the TODO list are not storing in the localStorage (and are not showing).
I would appreciate any help with that task.
How can I simplify the code? (without using any additional libraries and frameworks (ex.jquery etc.))
Here is my code:
let inputTask = document.getElementById('toDoEl');
let editTask = document.getElementById('editTask');
let checkTask = document.getElementById('list');
let emptyList = document.getElementById('emptyList');
let items = [];
let id = [];
let labelToEdit = null;
const empty = 0;
let pages = ['index', 'add', 'modify'];
load();
function load() {
items = loadFromLocalStorage();
id = getNextId();
items.forEach(item => renderItem(item));
}
function show(shown) {
location.href = '#' + shown;
pages.forEach(function(page) {
document.getElementById(page).style.display = 'none';
});
document.getElementById(shown).style.display = 'block';
return false;
}
function getNextId() {
for (let i = 0; i<items.length; i++) {
let item = items[i];
if (item.id > id) {
id = item.id;
}
}
id++;
return id;
}
function loadFromLocalStorage() {
let localStorageItems = localStorage.getItem('items');
if (localStorageItems === null) {
return [];
}
return JSON.parse(localStorageItems);
}
function saveToLocalStorage() {
localStorage.setItem('items', JSON.stringify(items));
}
function setChecked(checkbox, isDone) {
if (isDone) {
checkbox.classList.add('checked');
checkbox.src = 'https://image.ibb.co/b1WeN9/done_s.png';
let newPosition = checkTask.childElementCount - 1;
let listItem = checkbox.parentNode;
listItem.classList.add('checked');
checkTask.removeChild(listItem);
checkTask.appendChild(listItem);
} else {
checkbox.classList.remove('checked');
checkbox.src = 'https://image.ibb.co/nqRqUp/todo_s.png';
let listItem = checkbox.parentNode;
listItem.classList.remove('checked');
}
}
function renderItem(item) {
let listItem = document.getElementById('item_template').cloneNode(true);
listItem.style.display = 'block';
listItem.setAttribute('data-id', item.id);
let label = listItem.querySelector('label');
label.innerText = item.description;
let checkbox = listItem.querySelector('input');
checkTask.appendChild(listItem);
setChecked(checkbox, item.isDone);
emptyList.style.display = 'none';
return listItem;
}
function createNewElement(task, isDone) {
let item = { isDone, id: id++, description: task };
items.push(item);
saveToLocalStorage();
renderItem(item);
}
function addTask() {
if (inputTask.value) {
createNewElement(inputTask.value, false);
inputTask.value = '';
show('index');
}
}
function modifyTask() {
if (editTask.value) {
let item = findItem(labelToEdit);
item.description = editTask.value;
labelToEdit.innerText = editTask.value;
saveToLocalStorage();
show('index');
}
}
function findItem(child) {
let listItem = child.parentNode;
let id = listItem.getAttribute('data-id');
id = parseInt(id);
let item = items.find(item => item.id === id);
return item;
}
// Chanhe img to checked
function modifyItem(label) {
labelToEdit = label;
editTask.value = label.innerText;
show('modify');
editTask.focus();
editTask.select();
}
function checkItem(checkbox) {
let item = findItem(checkbox);
if (item === null) {
return;
}
item.isDone = !item.isDone;
saveToLocalStorage();
setChecked(checkbox, item.isDone);
}
function deleteItem(input) {
let listItem = input.parentNode;
let id = listItem.getAttribute('data-id');
id= parseInt(id);
for (let i in items) {
if (items[i].id === id) {
items.splice(i, 1);
break;
}
}
if (items.length === empty) {
emptyList.style.display = 'block';
}
saveToLocalStorage();
listItem.parentNode.removeChild(listItem);
}
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
h2, li, #notification {
text-align: center;
}
h2 {
font-weight: normal;
margin: 0 auto;
padding-top: 20px;
padding-bottom: 20px;
}
#root {
width: 400px;
height: 550px;
margin: 0 auto;
position: relative;
}
#root>ul {
display: block;
}
#addButton {
display: block;
margin: 0 auto;
}
.checkbox, .delete {
height: 24px;
bottom: 0;
}
.checkbox {
float: left;
}
.delete {
float: right;
}
ul {
margin: 20px 30px 0 30px;
padding-top: 20px;
padding-left: 20px;
text-align: center;
}
#toDoEl {
width: 50%;
}
li {
width: 100%;
list-style: none;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px auto;
}
label {
margin: 0 auto;
text-align: justify;
text-justify: inter-word;
}
label:hover {
cursor: auto;
}
li.checked {
background-color: gray;
}
span.button {
cursor: pointer;
}
#add, #modify {
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Homework 12 - Simple TODO List</title>
<link rel="stylesheet" href="./assets/styles.css">
</head>
<body>
<div id="root">
<!--Main page-->
<div id="index">
<h2>Simple TODO Application</h2>
<button class="button" id="addButton" onclick="show('add')">Add New Task</button>
<p id="emptyList">TODO is empty</p>
<ul id="list">
<li id="item_template" style="display: none">
<input class="checkbox" type="image" alt="checkbox" src="https://image.ibb.co/nqRqUp/todo_s.png" onclick="checkItem(this)">
<label onclick="modifyItem(this)"></label>
<input id="delete" class="delete" type="image" alt="remove" src="https://image.ibb.co/dpmqUp/remove_s.jpg" onclick="deleteItem(this)">
</li>
</ul>
</div>
<!--Add page-->
<div id="add">
<h2>Add Task</h2>
<input type="text" id="toDoEl">
<button class="button cancel" onclick="show('index')">Cancel</button>
<button class="button save" onclick="addTask()">Save changes</button>
</div>
<!--Modify page-->
<div id="modify">
<h2>Modify item</h2>
<input type="text" id="editTask">
<button class="button cancel" onclick="show('index')">Cancel</button>
<button class="button save" onclick="modifyTask()">Save changes</button>
</div>
</div>
<script src="./src/app.js"></script>
</body>
</html>
Your code does appear to work. If you console.log(JSON.parse(localStorageItems)) right above line 49 in the loadFromLocalStorage function, it shows as expected in the console. Also, upon refreshing the items persist.
If what you mean is that you're checking localStorage and you don't see the items, it might be that you're looking at the preview version of localStorage. (I'm assuming you're using Chrome.) Hover over the top of the empty section and pull down, this should reveal the values stored. If you click on one, it should show in the preview section. I think this was a Chrome dev tools UI change recently implemented.
I checked your code in Codepen and it works.
i am doing the library project from "odin project" website and i am having trouble completing it. my idea is to access the cards particular index in the "library" array of objects, but i am having trouble doing so. my idea is to have a function that creates some type of id from its place in the array ( such as its index ) and use that as access for my delete button. any suggestions? i appreciate your time here is my codepen link
//constructor to add a book to
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
//array of books
const library = [];
//hides and unhides forms
const hide = () => {
var form = document.querySelector("#hide");
if (form.style.display === "none") {
form.style.cssText =
"display: block; display: flex; justify-content: center; margin-bottom: 150px";
} else {
form.style.display = "none";
}
};
//creates form, takes input,creates card, resets and runs hide function when done
const addBookCard = () => {
const bookName = document.querySelector('input[name="bookName"]').value;
const authorName = document.querySelector('input[name="authorName"]').value;
const numPages = document.querySelector('input[name="numPages"]').value;
library.push(new Book(bookName, authorName, numPages));
//just stating variables used within my function
const container = document.querySelector(".flex-row");
const createCard = document.createElement("div");
const divTitle = document.createElement("p");
const divAuthor = document.createElement("p");
const divPages = document.createElement("p");
const deleteBtn = document.createElement("button");
//using a class from my css file
createCard.classList.add("card");
createCard.setAttribute("id","id_num")
deleteBtn.setAttribute("onclick", "remove()")
deleteBtn.setAttribute('id','delBtn')
//geting all info from library
divTitle.textContent = "Title: " + bookName
divAuthor.textContent = "Author: " + authorName
divPages.textContent = "Number of Pages: " + numPages
deleteBtn.textContent = "Delete This Book";
//adding it all to my html
container.appendChild(createCard);
createCard.appendChild(divTitle);
createCard.appendChild(divAuthor);
createCard.appendChild(divPages);
createCard.appendChild(deleteBtn);
document.getElementById("formReset").reset();
hide()
return false
};
var btn = document.querySelector('#newCard');
btn.onclick = addBookCard;
You can change library declaration from const to let.
Then you can push books together with their corresponding deleteBtn, that way you will be able to easily remove an entry that corresponds to the clicked deleteBtn
library.push([new Book(bookName, authorName, numPages), deleteBtn]);
And then you can add event listener on deleteBtn like this
deleteBtn.addEventListener('click', event => {
event.target.parentNode.remove();
library = library.filter(v => v[1] !== event.target);
});
Where the first line removes the element from the DOM, and the second line creates new library array without the removed entry.
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
}
//array of books
let library = [];
//hides and unhides forms
const hide = () => {
var form = document.querySelector("#hide");
if (form.style.display === "none") {
form.style.cssText =
"display: block; display: flex; justify-content: center; margin-bottom: 150px";
} else {
form.style.display = "none";
}
};
//creates form, takes input,creates card, resets and runs hide function when done
const addBookCard = () => {
const bookName = document.querySelector('input[name="bookName"]').value;
const authorName = document.querySelector('input[name="authorName"]').value;
const numPages = document.querySelector('input[name="numPages"]').value;
//just stating variables used within my function
const container = document.querySelector(".flex-row");
const createCard = document.createElement("div");
const divTitle = document.createElement("p");
const divAuthor = document.createElement("p");
const divPages = document.createElement("p");
const deleteBtn = document.createElement("button");
library.push([new Book(bookName, authorName, numPages), deleteBtn]);
deleteBtn.addEventListener('click', event => {
event.target.parentNode.remove();
library = library.filter(v => v[1] !== event.target);
});
//using a class from my css file
createCard.classList.add("card");
createCard.setAttribute("id","id_num")
deleteBtn.setAttribute('id','delBtn')
//geting all info from library
divTitle.textContent = "Title: " + bookName
divAuthor.textContent = "Author: " + authorName
divPages.textContent = "Number of Pages: " + numPages
deleteBtn.textContent = "Delete This Book";
//adding it all to my html
container.appendChild(createCard);
createCard.appendChild(divTitle);
createCard.appendChild(divAuthor);
createCard.appendChild(divPages);
createCard.appendChild(deleteBtn);
document.getElementById("formReset").reset();
hide()
return false
};
var btn = document.querySelector('#newCard');
btn.onclick = addBookCard;
function hello (){
for (var i = 0; i < library.length ;i++) {
console.log(library[i]);
}
}
body {
margin: 0 auto;
width: 960px;
//background: cyan;
}
.flex-row {
display: flex;
flex-wrap: wrap;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-row-form {
display: flex;
justify-content: center;
}
.flex-column-form {
display: flex;
flex-direction: column;
background: purple;
width: 45%;
padding: 20px;
border-radius: 5px;
border: 2px solid black;
color: white;
font-weight: 300;
font-size: 24px;
}
.card {
width: 33.33%;
text-align: center;
height: 200px;
border: 1px solid black;
padding: 20px;
margin: 10px;
border-radius: 10px;
}
.text {
padding-bottom: 20px;
font-weight: 300;
font-size: 20px;
}
p {
font-size: 20px;
font-weight: 400;
}
#newBook {
margin: 30px;
padding: 10px 20px;
cursor: pointer;
font-size: 16px;
color: #dff;
border-radius: 5px;
background: black;
}
#delBtn{
padding:10px;
border-radius:5px;
background:red;
color:white;
font-size:14px;
cursor: pointer;
}
<div id="display"></div>
<button id="newBook" onclick="hide()">New Book</button>
<div class="flex-row-form" id="hide" style= "display:none">
<form class="flex-column-form" id="formReset">
Book Name: <input type="text" name="bookName" value="Book Name" id="title"><br>
Author Name: <input type="text" name="authorName" value="Author Name " id="author"<br>
Number of Pages: <input type="text" name="numPages" value="# of Pages" id="pages" ><br>
<button id="newCard"> Add Book to Library</button>
</form>
</div>
<div class="flex-row">
</div>
And I have removed this line
deleteBtn.setAttribute("onclick", "remove()")
you don't need it anymore since I have added event listener for that button, and it was throwing an error because you didn't define remove function in your code.
I am making a javascript form that includes a question being answered with only the number 1-6 (multiple choice) when the user finishes the form, there will be a result showing a chart (ChartJS). I've made that, but I want to show the user below the chart as following. If statement 1 is 1 and If statement 2 is 3 and If statement 3 is 4 then show .... . Here is my code:
/*-----------------------------------------------------
REQUIRE
-------------------------------------------------------*/
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var minixhr = require('minixhr')
var chart = require('chart.js')
/*-----------------------------------------------------
THEME
-------------------------------------------------------*/
var font = 'Montserrat'
var yellow = 'hsla(52,35%,63%,1)'
var white = 'hsla(120,24%,96%,1)'
var violet = 'hsla(329,25%,45%,1)'
var lightBrown = 'hsla(29,21%,67%,1)'
var darkBrown = 'hsla(13,19%,45%,1)'
/*-----------------------------------------------------------------------------
LOADING FONT
-----------------------------------------------------------------------------*/
var links = ['https://fonts.googleapis.com/css?family=Montserrat']
var font = yo`<link href=${links[0]} rel='stylesheet' type='text/css'>`
document.head.appendChild(font)
/*-----------------------------------------------------------------------------
LOADING DATA
-----------------------------------------------------------------------------*/
var questions = [
`
Statement #1:
The next social network I build,
will definitely be for animals.
`,
`
Statement #2:
I really like to do my hobby
`,
`
Statement #3:
My friends say, my middle name should be "Halo".
`,
`
Statement #4:
Rhoma Irama is definitely one of my
favourite artists
`,
`
Statement #5:
I think I could spend all day just
sleeping at my couch
`,
`
Statement #6:
I have a really strong desire to succeed
`
]
var i = 0
var question = questions[i]
var results = []
var answerOptions = [1,2,3,4,5,6]
/*-----------------------------------------------------------------------------
QUIZ
-----------------------------------------------------------------------------*/
function quizComponent () {
var css = csjs`
.quiz {
background-color: ${yellow};
text-align: center;
font-family: 'Montserrat';
padding-bottom: 200px;
}
.welcome {
font-size: 4em;
padding: 50px;
color: ${darkBrown}
}
.question {
font-size: 2em;
color: ${white};
padding: 40px;
margin: 0 5%;
}
.answers {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin: 0 5%;
}
.answer {
background-color: ${violet};
padding: 15px;
margin: 5px;
border: 2px solid ${white};
border-radius: 30%;
}
.answer:hover {
background-color: ${lightBrown};
cursor: pointer;
}
.instruction {
color: ${violet};
font-size: 1em;
margin: 0 15%;
padding: 20px;
}
.results {
background-color: ${white};
text-align: center;
font-family: 'Montserrat', cursive;
padding-bottom: 200px;
}
.resultTitle{
font-size: 4em;
padding: 50px;
color: ${darkBrown}
}
.back {
display: flex;
justify-content: center;
}
.backImg {
height: 30px;
padding: 5px;
}
.backText {
color: ${white};
font-size: 25px;
}
.showChart {
font-size: 2em;
color: ${violet};
margin: 35px;
}
.showChart:hover {
color: ${yellow};
cursor: pointer;
}
.myChart {
width: 300px;
height: 300px;
}
`
function template () {
return yo`
<div class="${css.quiz}">
<div class="${css.welcome}">
IQ Test
</div>
<div class="${css.question}">
${question}
</div>
<div class="${css.answers}">
${answerOptions.map(x=>yo`<div class="${css.answer}" onclick=${nextQuestion(x)}>${x}</div>`)}
</div>
<div class="${css.instruction}">
Choose how strongly do you agree with the statement<br>
(1 - don't agree at all, 6 - completely agree)
</div>
<div class="${css.back}" onclick=${back}>
<img src="http://i.imgur.com/L6kXXEi.png" class="${css.backImg}">
<div class="${css.backText}">Back</div>
</div>
</div>
`
}
var element = template()
document.body.appendChild(element)
return element
function nextQuestion(id) {
return function () {
if (i < (questions.length-1)) {
results[i] = id
i = i+1
question = questions[i]
yo.update(element, template())
} else {
results[i] = id
sendData(results)
yo.update(element, seeResults(results))
}
}
}
function seeResults(data) {
var ctx = yo`<canvas class="${css.myChart}"></canvas>`
return yo`
<div class="${css.results}">
<div class="${css.resultTitle}">
Your Result
</div>
<div class="${css.showChart}" onclick=${function(){createChart(ctx, data)}}>
Click to see the chart
</div>
${ctx}
</div>
`
}
function back() {
if (i > 0) {
i = i-1
question = questions[i]
yo.update(element, template())
}
}
function sendData(results) {
var request = {
url : 'https://cobatest-964fd.firebaseio.com/results.json',
method : 'POST',
data : JSON.stringify(results)
}
minixhr(request)
}
function createChart(ctx, myData) {
minixhr('https://cobatest-964fd.firebaseio.com/results.json', responseHandler)
function responseHandler (data, response, xhr, header) {
var data = JSON.parse(data)
var keys = Object.keys(data)
var arrayOfAnswers = keys.map(x=>data[x])
var stats = arrayOfAnswers.reduce(function(currentResult,answer,i) {
var newResult=currentResult.map((x,count)=>(x*(i+1)+answer[count])/(i+2))
return newResult
}, myData)
var data = {
labels: [
"Caring", "Eager", "Pessimist",
"Hard-headed", "Lazy", "Ambitious"
],
datasets: [
{
label: "My score",
backgroundColor: "rgba(179,181,198,0.2)",
borderColor: "rgba(179,181,198,1)",
pointBackgroundColor: "rgba(179,181,198,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(179,181,198,1)",
data: myData
},
]
}
var myChart = new Chart(ctx, {
type: 'radar',
data: data,
options: {
scale: {
scale: [1,2,3,4,5,6],
ticks: {
beginAtZero: true
}
}
}
})
}
}
}
quizComponent()
Please do help! thank you
Just like onclick is an event, onsubmit is one too.
From w3schools:
in HTML: <element onsubmit="myScript">
in JS: object.onsubmit = function(){myScript};
in JS with eventListener:object.addEventListener("submit", myScript);
You can check it out on w3 schools:
onsubmit event
onsubmit attribute
more