After Click Event Instead of Showing all Notes Display only Current Note - javascript

Program starts with displaying all notes from localstore, but when I click the addButton it display my current note only.
I want to show all the notes and after click event new note will add with previous notes.
let addButton = document.querySelector(".addBtn");
let userNotes = [];
displayNotes();
//addButton Event Listner
addButton.addEventListener("click", function(e) {
e.preventDefault();
//get the user inputs
let userInputs = {
title: document.getElementById("title_input").value,
description: document.getElementById("des_input").value
};
//push user inputs to arrays
userNotes.push(userInputs);
document.querySelector("form").reset();
//store to the localstorage
localStorage.setItem("Notes", JSON.stringify(userNotes));
//display to the user
displayNotes();
});
function displayNotes() {
let gettingNotes = localStorage.getItem("Notes");
let allNotes = JSON.parse(gettingNotes);
let html = "";
allNotes.forEach(element => {
html += `
<div class="single-item">
<h2 class="single-item-title">
${element.title}
</h2>
<p class="single-item-description">
${element.description}
</p>
</div>
`;
});
document.querySelector(".item-list").innerHTML = html;
}

It happens because you set userNotes to be an empty array and you add only your current note. Try to initialize userNotes with a value from localStorage, i.e
let userNotes = JSON.parse(localStorage.getItem('Notes')) || []
Also, then you are able to use userNotes variable in displayNotes function, instead of allNotes.

Related

Why are copies of whats in my array posting?

i want the value from my input to render on my page when i click on my button to add text to my page. For some reason with the current code that i have, the new value from my input is displayed in addition to a copy of what was already there, so basically previous input values are showing more than once on the front end as opposed to a new item just being added to the list
heres a link to the codepen so you can see what happens https://codepen.io/matthew-angel/pen/jOmJLBW
// Log out "Button clicked!" when the user clicks the "SAVE INPUT" button
let myLeads = []
const button = document.querySelector("#input-btn")
const inputEl = document.querySelector("#input-el")
// let inputText = inputEl.value
const ulEl = document.querySelector("#ul-el")
button.addEventListener("click", addText)
function addText() {
console.log(inputEl.value)
myLeads.push(inputEl.value)
console.log(myLeads)
render()
}
function render(){
for(let i = 0; i < myLeads.length; i++) {
// create element
// set text content
// append to ul
let li = document.createElement('li')
li.innerText += myLeads[i]
ulEl.appendChild(li)
console.log(li)
console.log(ulEl)
console.log( li.textContent)
}
}

Onclick event inside HTML row that changes the value of the previous element in HTML row

I have a function addBookToList() that creates an HTML row of elements. I have a button inside the row along with other elements.
I'm trying to add an "onclick" event with a toggle() function to that button in order to change the read status of a book (yes or no).
Is there a way I can click on that button and have the function toggle() changing the value of the previous element sibling (value.read) and back? I added the event but I don't know how to target the button and value.read.
// Book constructor
function Book(author, title, pages, read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
}
// Empty array to store books
let myLibrary = [];
// Event listener when clicking SUBMIT button on the form
form.addEventListener('submit', (e) => {
e.preventDefault();
// Hide form and show home page
document.querySelector('.table-box').style.display = 'block';
document.querySelector('.para-div').style.display = 'block';
form.style.display = 'none';
// Get values from User
let title = document.querySelector('#title').value;
let author = document.querySelector('#author').value;
let pages = document.querySelector('#num-pages').value;
let read = getRead();
// Instantiate book
const book = new Book(author, title, pages, read);
// Push book to the library, show it on the UI and clear the form
myLibrary.push(book);
addBookToList();
// Add book to Local Storage
addBook();
// Show success alert
showAlert('Book added!', 'success');
// Clear form
form.reset();
});
// Get value of radio button
function getRead() {
const radioBtn = document.querySelectorAll('input[name="radio"]');
let selectValue;
for(const i of radioBtn) {
if(i.checked) {
selectValue = i.value;
}
}
return selectValue;
}
function addBookToList() {
// Create new row element
const row = document.createElement('tr');
// Loop through myLibrary array
myLibrary.forEach(value => {
// Add the book to the table
row.innerHTML = `
<td>${value.title}</td>
<td>${value.author}</td>
<td>${value.pages}</td>
<td>${value.read}</td>
<td><button class="toggle" onclick="toggle()">Change read status</button></td>
<td>X</td>`;
});
// Append the row to list
list.appendChild(row);
}
In your function addBookToList, you can use IIFE.
function addBookToList() {
// Create new row element
const row = document.createElement('tr');
// Loop through myLibrary array
myLibrary.forEach(value => {
// Add the book to the table
row.innerHTML = `
<td>${value.title}</td>
<td>${value.author}</td>
<td>${value.pages}</td>
<td>${value.read}</td>
<td><button class="toggle">Change read status</button></td>
<td>X</td>`;
});
// Append the row to list
list.appendChild(row);
const toggleBtn = document.querySelector('.toggle');
toggleBtn.onclick = (function(value) {
return function(){
// update read property on value
value.read = !value.read;
}
})(value);
}

add event listener to the dynamically generated elements captured from API using Javascript

I am working on an app which fetch the data from API and create a list of the books based on the data received from API. it's an API which gives book titles and information. I generated dynamic li elements and generated a button inside the li. each button has a hidden input element which keep book titles in it. the problem is I'm trying to define a onclick event listener for buttons, since buttons are generated dynamically they don't have id. I want to create an event listener for buttons so that once one specific button is clicked the value of hidden input element that is defined inside the button is passed. I couldn't figure out a way to do that. how to make it to understand which specific button has been clicked so it return the input value that is attached to it.
any help would be really appreciated.
here is a portion of my code.
async function overViewMaker(){
const response = await fetch(api_url_overview.concat(api_key));
let data = await response.json();
data = data.results.lists;
data.forEach(book => {
let mybook = book.books;
mybook.forEach(eachbook => {
var book_div = document.getElementById('book_list');
var liTag = document.createElement("li");
var aTag = document.createElement("buttom");
var inpuHidden = document.createElement("input");
inpuHidden.setAttribute("type", "hidden");
inpuHidden.value = eachbook.title;
aTag.appendChild(inpuHidden);
liTag.appendChild(aTag);
book_div.appendChild(liTag);
});
});
}
Each button is already an element object and so you can use addEventListener directly on the element.
async function overViewMaker() {
const response = await fetch(api_url_overview.concat(api_key));
let data = await response.json();
data = data.results.lists;
// moved book_div out of for loop so it doesn't need to be re-queried for every book
var book_div = document.getElementById("book_list");
data.forEach((book) => {
let mybook = book.books;
mybook.forEach((eachbook) => {
var liTag = document.createElement("li");
var aTag = document.createElement("button");
var inpuHidden = document.createElement("input");
inpuHidden.setAttribute("type", "hidden");
inpuHidden.value = eachbook.title;
aTag.appendChild(inpuHidden);
aTag.addEventListener("click", (ev) => {
// you don't need to get book title from the hidden input element since it is in the scope
// inputHidden.value is also accessible from inside of here
const title = eachBook.title;
console.log(title);
});
liTag.appendChild(aTag);
book_div.appendChild(liTag);
});
});

How to disable and enable button in JavaScript

I am currently building a shopping list app that contains a form, input box and submit button. My goal is to allow the user to input values into the form up until there has been 6 items listed on the page; after it has reached 6, I would like to disable the button so that no more values can be added. However, if a user deletes an item (e.g. the list goes down to 5 items), I would like for the button to be enabled until it reaches 6 and then continue the same routine over again.
I have tried to use an array and an "if else if statement" specifying the conditions, but that has not worked. Below is the JS code that I have tried.
let items = [];
let list = document.querySelector('ul');
let input = document.querySelector('input');
let button = document.querySelector('button').addEventListener('click', buttonClick);
function buttonClick() {
let myItem = input.value;
console.log(items)
items.push(input.value);
input.value = '';
if (items.length === 6) {
let e = document.querySelector('button').disabled = true;
items.length = 0;
} else if (button.disabled === false) {
button.disabled = true;
}
Here is the HTML
<img src='img/paper.jpg'>
<div class='second'>
<label for="item">Enter a new item:</label>
<input type="text" name="item" id="item">
<button>Add item</button>
</div>
<ul>
</ul>
</div>
I continue to receive an error message on the console stating, "Cannot read property disabled of undefined".
I think you should change this line of your code
let button = document.querySelector('button').addEventListener('click', buttonClick);
To this one
let button = document.querySelector('button');
button = .addEventListener('click', buttonClick);
And then you can make it disabled or not without selecting it again
button.disabled = true or button.disabled = false
Your need to get your button by id.
Change this:
let e = document.querySelector('button').disabled = true;
to this:
document.getElementById("ID_OF_BUTTON").disabled = true;
Remember to change "ID_OF_BUTTON" to id you put on your button html.
I think chaining the method in below code is causing the issue:
let button = document.querySelector('button').addEventListener('click', buttonClick);
Solution:
1.First get the button control:
let button=document.querySelector('button');
2.Attach event handlor.
button.addEventListener('click',buttonClick);

Struggling to keep HTML and JS separate

I'm creating a basic to do list in Vanilla JS, I'm using Handlebars to keep the HTML & JS separate.
Everything was going fine till I came to the delete method. Because my delete button is inside my HTML and not created inside my JS I'm finding it hard to select and delete items from the array.
I thought I'd found a way around it by looping over them but the issue with this is it tries to grab the buttons on page load, and so it returns always an empty array as on page load there are no delete buttons as no to do has been added at that point.
I've also tried putting the delete method inside the add method to counter this but this also presented issues.
Simply, can someone give me an example of a working delete method that removes the relevant item from the array using splice.
Cheers
HTML
<input id="add-to-do-value" type="text" placeholder="Add to do">
<button id="add-to-do">Add</button>
<div id="to-do-app"></div>
<script type="text/javascript" src="js/handlebars.js"></script>
<script id="to-do-template" type="text/template">
<ul>
{{#this}}
<div>
<li id={{id}}>
{{value}}
<button class="delete-btn" id={{id}}>Delete</button>
</li>
</div>
{{/this}}
</ul>
</script>
<script type="text/javascript" src="js/app.js"></script>
JS
(function() {
// Data array to store to dos
var data = [];
// Cache dom
var toDoApp = document.getElementById('to-do-app');
var toDoTemplate = document.getElementById('to-do-template');
var addToDo = document.getElementById('add-to-do');
var addToDoValue = document.getElementById('add-to-do-value');
var toDoTemplate = Handlebars.compile(toDoTemplate.innerHTML);
// Render HTML
var render = function() {
toDoApp.innerHTML = toDoTemplate(data);
}
// Add to dos
var add = function() {
var toDoValue = addToDoValue.value;
if(toDoValue) {
var toDoObj = {
value: toDoValue,
id: Date.now(),
}
data.push(toDoObj);
}
render();
}
// Delete to dos
var deleteBtn = document.querySelectorAll('.delete-btn');
for(i=0; i<deleteBtn.length; i++) {
deleteBtn[i].addEventListener("click", function(){
for(j=0; j<data.length; j++) {
if(data[j].id == this.id) {
data.splice(data[j], 1);
render();
}
}
});
}
// Bind events
addToDo.addEventListener("click", add);
})();
The fact that you're using Handlebars makes the whole thing unnecessary complex. I would suggest that you don't use innerHTML, but other parts of the DOM API instead to be able to easily access the elements you need. For more complex todo items, I would consider using <template>s.
Anyway, you have to bind the event listener for removing the item when you create the new item (i.e. in the add function):
var todos = [];
var input = document.querySelector('input');
var addButton = document.querySelector('button');
var container = document.querySelector('ul');
var add = function () {
var content = input.value;
input.value = '';
var id = Date.now();
var li = document.createElement('li');
li.appendChild(document.createTextNode(content));
var button = document.createElement('button');
button.textContent = 'Delete';
button.addEventListener('click', remove.bind(null, id));
li.appendChild(button);
todos.push({ content, id, element: li });
container.appendChild(li);
};
var remove = function (id) {
var todo = todos.find(todo => todo.id === id);
container.removeChild(todo.element);
todos = todos.filter(t => t !== todo);
};
addButton.addEventListener('click', add);
<input type="text" placeholder="Add to do">
<button>Add</button>
<ul></ul>

Categories