I have passed my DOM element as a string here.
function showNotes() {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
let html = "";
notesObj.forEach(function(element, index) {
html += `<div class="noteCard card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Title: ${element.title}</h5>
<p class="card-text">${element.text}</p>
<a href="#" id="${index}"onclick="deleteNotes(this.id)" class="card-link" >Delete Note</a>
Important
</div>
</div>`;
});
I want to give a style to the card. When an user clicks the link "Important" (as mentioned in the DOM), the corresponding card color should be changed. So I am trying to access the "noteCard" class.
Here is my markNotes() function
function markNotes(index) {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
noteStyl = document.querySelectorAll('.noteCard')[0];
noteStyl.style.color = "red";
console.log("Color should be applied")
localStorage.setItem("notes", JSON.stringify(notesObj));
showNotes();
}
I have tried the following things also but nothing works out.
noteStyl = document.getElementsByClassName('noteCard')[0]
noteStyl = document.querySelector('.noteCard')[0];
With this code, when I am clicking the link "Important" nothing is going to change except the printing of "Color should be applied".
So there must be a problem in accessing the DOM file. I am really stuck in it.
Thanks in advance
See below code and comments I added I commented your localStorage code and added my dummy code for demo.
function showNotes() {
let notes = [{
title: 'title1',
text: 'text1'
},
{
title: 'title2',
text: 'text2'
},
{
title: 'title3',
text: 'text3'
}
];
notesObj = notes;
/* if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
} */
let html = "";
notesObj.forEach(function(element, index) {
html += `<div class="noteCard card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Title: ${element.title}</h5>
<p class="card-text">${element.text}</p>
<a href="#" id="${index}"onclick="deleteNotes(this.id)" class="card-link" >Delete Note</a>
Important
</div>
</div>`;
});
document.getElementById("html").innerHTML = html; // to insert data into HTML
}
showNotes() // calling function first time
function markNotes(index) {
console.log('index', index)
/*let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}*/
noteStyl = document.querySelectorAll('.noteCard')[index];
noteStyl.style.color = "red";
console.log("Color should be applied")
localStorage.setItem("notes", JSON.stringify(notesObj));
//showNotes(); // See I have commented this code
}
<div id="html">
</div>
There is nothing wrong with accessing the DOM. I think you are trying to access an element that is not on the page.
Are you displaying the html on the page at the end of showNotes function?
You can do so by: someDiv.innerHTML = html.
Update
to access a specific card (not always the first one) maybe you can set an id for each card with its index example: card-${index}, then accessing it with .getElementById
Update #2
You are storing notesObj as an array, and in the loop (in showNotes) you are creating a static style. So you need to update the object styles in notesObj
So instead of setting the style, create a styles object:
function markNotes(index) {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
if(!notesObj[index].styles) notesObj[index].styles = {};
notesObj[index].styles.color = "red";
localStorage.setItem("notes", JSON.stringify(notesObj));
showNotes();
}
Then apply it in the showNotes:
notesObj.forEach(function(element, index) {
style = "";
if(element.styles) {
console.log(element.styles);
for (let key in element.styles) {
style += `${key}: ${element.styles[key]}`;
}
}
console.log(style);
html += `<div class="noteCard card" style="width: 18rem; ${style}">
<div class="card-body">
<h5 class="card-title">Title: ${element.title}</h5>
<p class="card-text">${element.text}</p>
<a href="#" id="${index}"onclick="deleteNotes(this.id)" class="card-link" >Delete Note</a>
Important
</div>
</div>`;
});
Related
my cart is only work for data to localstorage but i dont know how can i make this icon switch after click add , than icon change function to remove.
i use awesome font heart for button click :
<a data-id='productID' data-link='productUrl' data-title='productItem' onclick='addItem(this)' title='add to cart'><i class='fa-regular fa-heart fa-xl'></i></a>
<table class='mt-5 table table-bordered' id='collection'></table>
here is script code
class CartItem {
constructor(url, reTitle, reId) {
this.url = url
this.reTitle = reTitle
this.reId = reId
}
}
class LocalCart {
static key = "askCollection"
static getLocalCartItems() {
let cartMap = new Map()
const cart = localStorage.getItem(LocalCart.key)
if (cart === null || cart.length === 0) return cartMap
return new Map(Object.entries(JSON.parse(cart)))
}
static addItemToLocalCart(id, item) {
let cart = LocalCart.getLocalCartItems()
if (cart.has(id)) {
} else
cart.set(id, item)
localStorage.setItem(LocalCart.key, JSON.stringify(Object.fromEntries(cart)))
updateCartUI()
}
static removeItemFromCart(id) {
let cart = LocalCart.getLocalCartItems()
if (cart.has(id)) {
cart.delete(id)
}
if (cart.length === 0)
localStorage.clear()
else
localStorage.setItem(LocalCart.key, JSON.stringify(Object.fromEntries(cart)))
updateCartUI()
}
}
function addItem(e) {
const url = e.dataset.link;
const reTitle = e.dataset.title;
const reId = e.dataset.id;
const item = new CartItem(url, reTitle, reId)
LocalCart.addItemToLocalCart(url, item)
}
function updateCartUI() {
const cartWrapper = document.querySelector('#collection')
cartWrapper.innerHTML = ""
const items = LocalCart.getLocalCartItems()
if (items === 0) return
let count = 0
for (const [key, value] of items.entries()) {
const cartItem = document.createElement('tr')
count += 1;
cartItem.innerHTML =
`
<td width="370" class="record" style="padding:5px">${value.reTitle}</td>
<td width="370" class="record" style="padding:5px">${value.reTitle}</td>
<td width="30" class="record-de"><i class="fa-regular fa-circle-minus"></i></td>
`
cartItem.querySelector('.record-de').addEventListener('click', () => {
LocalCart.removeItemFromCart(key)
})
cartWrapper.append(cartItem)
}
}
document.addEventListener('DOMContentLoaded', () => {
updateCartUI()
})
If fa-heart clicked then save to localstorare (fa-heart change from fa-regular to fa-solid)
if page reload, the fa-heart still in solid icon.
and can the fa-heart change function (toggle switch from add to remove if data has in localstorage)
i try it : https://jsfiddle.net/ceunahteuing/ypq95j3u/15/
Thanks in advance.
I am working with program that will randomly choose who is making a Christmas gift to whom.
I've created an empty array. When you add a "player" it's pushing the name into two different arrays. Players[] and Players2[].
When you start a draw. The program writes the names of the Players[] on the left hand side and on the right side it writes the drawn names from Players2[].
Every Player from Players2[], after being drawn, is being deleted from the array so in the end we have an empty Players2[] array and full Players[] array.
The problem is: I can't make a working if statement that is checking if the person will not draw himself...
let Players = [];
let Players2 = [];
const addBTN = document.getElementById('addBTN');
const onlyLetters = /^[a-zżźćóęśńłA-ZŻŹĆÓŁĘŚŃŁ ]+$/;
const refreshBTN = document.getElementById('refreshBTN');
const warningBTNyes = document.getElementById('warning-button-yes');
const warningBTNno = document.getElementById('warning-button-no');
const playersList = document.getElementById('playersList');
const playersList2 = document.getElementById('playersList2');
const startBTN = document.getElementById('startBTN');
const drawLotsBTN = document.getElementById('drawLotsBTN');
addBTN.addEventListener('click', function() {
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
console.log('error_empty_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Wpisz imię osoby!";
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Dodaj kolejną osobę.";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
});
refreshBTN.addEventListener('click', function() {
document.getElementById('warning').style.display = "block";
});
warningBTNyes.addEventListener('click', function() {
location.reload(true);
document.getElementById('addPLAYER').value = "";
});
warningBTNno.addEventListener('click', function() {
document.getElementById('warning').style.display = "none";
});
startBTN.addEventListener('click', function() {
drawLotsBTN.disabled = false;
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Zaczynasz losowanie!";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
document.getElementById('addPLAYER').disabled = true;
});
drawLotsBTN.addEventListener('click', function() {
for (let i = 0; i = Players2.length; i++) {
if (Players2.length > 0) {
randomPerson = Math.floor(Math.random() * Players2.length);
if (randomPerson != Players.indexOf(i)) {
console.log(Players2[randomPerson]);
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players2[randomPerson];
Players2.splice(randomPerson, 1);
}
} else {
console.log('error_empty_array');
}
}
});
<div id="warning" class="warning">
<div class="warning-flex">
<h1>Wszelkie wpisane imiona zostaną usunięte</h1>
<div class="warning-buttons">
<button id="warning-button-yes" class="warning-button-yes">Tak</button>
<button id="warning-button-no" class="warning-button no">Nie</button>
</div>
</div>
</div>
<div class="lotteryContainer">
<div class="left">
<p>dodaj osobę</p>
<div class="addPerson">
<input required id="addPLAYER" type="text">
<button id="addBTN">+</button>
<p id="errorMSG"></p>
<div class="refresh">
<button id="refreshBTN">Od nowa</button>
<button id="startBTN">Start</button>
</div>
</div>
</div>
<div class="right">
<p>Uczestnicy</p>
<div class="tables">
<div class="tableLeft">
<p id=playersList></p>
</div>
<div class="tableRight">
<p id="playersList2"></p>
</div>
</div>
<button id="drawLotsBTN">Losuj</button>
</div>
</div>
<script src="app.js"></script>
Now if I understand what your program aims to do, there is a simple algorithm for it.
How I understand your goal:
You have a list of persons who are going to give presents to each other. (like in secret Santa). It is random who will give to who, but each person gives and receives one gift.
How to implement it (i'd normaly use maps, but I am guessing you are more comfortable with arrays):
players = ["Adam", "Bret", "Clay", "Donald"];
players.sort(function(a, b){return 0.5 - Math.random()}); // shuffles array
gives_to = [...players]; // copy values of array
gives_to.push(gives_to.shift()); // let the first element be the last
Here the first player (players[0]) will give to gives_to[0] and the second to gives_to[1] etc.
I've created this JS script trying to use Trygve Ruud algorithm but it doesn't work like desired.
drawLotsBTN.addEventListener('click', function(){
if(Players.length > 0) {
console.log(Players)
Players.sort(function(a, b){
return 0.5 - Math.random();
});
for(let i = 0; i < Players.length; i++){
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players[i];
}
}
else{
console.log('error_empty_array');
}
});
I have this help dialog and some reason my information texts are not showing as soon as the dialog is open. It only start to show when I click the subsection so just wonder how I can display it as soon as the user open the dialog box. Any suggestion or help will be really appreciated.
HTML
//Clicking this will take the user each subsection
<div *ngFor="let subSection of mappedSecSub | async; let last=last">
<div *ngIf="subSection.parentId == section.id;" (click)="clicked(subSection.id, section.id)">
<a mat-list-item>{{subSection.name}}
<mat-divider *ngIf="!last" class="solid"></mat-divider>
</a>
</div>
</div>
// This display the informations text
<div class="column right">
<div *ngFor="let section of targetSectionGroup">
<h1 *ngIf="section.parentId == null" class="hint">{{section?.name}}</h1>
</div>
<div *ngFor="let section of targetSectionGroup">
<div *ngIf="section.parentId != null">
<h2 id="s{{section.id}}ss{{section.parentId}}" class="hint">{{section?.name}}</h2>
<p class="multi_lines_text" [innerHTML]="section?.text"></p>
</div>
</div>
</div>
TS
mappedSections: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([]);
mappedSecSub = this.mappedSections.asObservable()
targetSection: { id, name, parentId, text };
targetSectionGroup: { id, name, parentId, text }[] = [];
ngOnInit(): void {
this.fetchData();
}
fetchData = () => {
this.HelpService.getHelp().subscribe(res => {
this.mappedSections.next(res['res'])
let newMappedSection = this.mappedSections.getValue()
for (let i = 0; i < newMappedSection.length; i++) {
const element = newMappedSection[i];
if (element.parentId) {
this.targetSection = element;
break
}
}
})
}
clicked(id, parentId) {
this.targetSectionGroup = [];
let data = this.mappedSections.getValue()
for (let i = 0; i < data.length; i++) {
if (data[i].parentId == parentId || data[i].id == parentId) {
this.targetSectionGroup.push(data[i]);
}
if (data[i].id === id) {
this.targetSection = data[i]
}
}
document.querySelector(`#s${id}ss${parentId}`).scrollIntoView({ behavior: 'smooth' })
}
Right now the information text only show up when I click the subsections. I want to show it as soon as the help dialog is open.
I guess this should work
fetchData = () => {
this.HelpService.getHelp().subscribe(res => {
this.mappedSections.next(res['res']);
const response = res['res'];
this.clicked(response.id, response.parentId);
let newMappedSection = this.mappedSections.getValue()
for (let i = 0; i < newMappedSection.length; i++) {
const element = newMappedSection[i];
if (element.parentId) {
this.targetSection = element;
break
}
}
})
}
I'm making a movie sorter list, you enter the title and then the rating and it will show you the movies in order by rating. I have an array of objects and I managed to sort the array by rating, but I can't find a way to actually display the array in order on the HTML DOM.
I've tried for loops and forEach's but they don't work the way I want.
const movieTitle = document.querySelector(".movie-title");
const movieRating = document.querySelector(".movie-rating");
const movieList = document.querySelector(".movie-list");
const sortBtn = document.querySelector(".btn");
let movieStorage = [];
function sendMovie() {
if(event.keyCode == 13) {
if(movieTitle.value != "" && movieRating.value != "") {
title = movieTitle.value;
rating = parseInt(movieRating.value);
movieStorage.push({
title: title,
rating: rating
});
// If rating of a is bigger than rating of b return 1, if not return -1
movieStorage.sort((a, b) => (a.rating > b.rating) ? -1 : 1);
console.log(movieStorage);
addMovieToList(title, rating);
movieTitle.value = "";
movieRating.value = "";
} else {
console.log("Fields missing");
}
}
}
function addMovieToList(title, rating) {
const div = document.createElement("div");
div.className = "list-items";
div.innerHTML = `
<div class="item-title">
<p>${title}</p>
</div>
<div class="item-rating">
<p>${rating}</p>
</div>
<div class="item-delete">
<i class="fa fa-trash trash-icon delete"></i>
</div>
`;
movieList.appendChild(div);
}
function sortByRating(element) {
for(let i = 0; i < movieStorage.length; i++) {
element.innerHTML = `
<div class="item-title">
<p>${movieStorage[i].title}</p>
</div>
<div class="item-rating">
<p>${movieStorage[i].rating}</p>
</div>
<div class="item-delete">
<i class="fa fa-trash trash-icon delete"></i>
</div>
`;
}
}
document.addEventListener("click", (e) => {
const deleteIcon = e.target;
const item = document.querySelector(".list-items");
if(deleteIcon.classList.contains("delete")) {
deleteIcon.parentElement.parentElement.remove(item);
}
})
tldr demo
After sorting the array, you need a way to reference movie divs to sort them. There are many ways to do it, what I chose is using id. When you create movie <div>, give it an ID unique for each movie name:
// Simple function to generate hash number for each string
function hashStr(stringValue) {
var hash = 0, i, chr;
if (stringValue.length === 0) return hash;
for (i = 0; i < stringValue.length; i++) {
chr = stringValue.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
const MOVIES = [
{name: "a", rating: 3},
{name: "b", rating: 6},
{name: "c", rating: 3},
{name: "d", rating: 2},
{name: "e", rating: 1},
];
function showMovies() {
const moviesDiv = document.querySelector("#movies");
for(const movie of MOVIES)
{
const id = "movie-"+hashStr(movie.name);
// If there's no element with the ID, we need to create the DIV for the movie
if(!document.querySelector("#"+id)) {
const elm = document.createElement("div");
elm.appendChild(new Text(movie.name + " ("+movie.rating+"/10)"));
elm.id = id;
elm.classList.add("movie");
moviesDiv.appendChild(elm);
}
}
}
Then, when sorting, you can reference each movie by ID:
// Sort movies using given property (eg. "name")
// The second param determines sort direction
function sortBy(property, ascending=true) {
MOVIES.sort((a,b) =>{
return cmp(a[property], b[property], ascending);
});
// Now after sorting the array, we can sort the HTML elements
const moviesDiv = document.querySelector("#movies");
let lastMovie = null;
for(const movie of MOVIES)
{
const id = "#movie-"+hashStr(movie.name);
const movieDiv = document.querySelector(id);
console.log(id, movieDiv);
// If created
if(movieDiv) {
// remove and append after last processed movie (for the first movie, this will append to top)
moviesDiv.insertBefore(movieDiv, lastMovie);
}
}
}
// Compare string and number, makes no sense for other types
function cmp(a,b, ascending=true) {
if(typeof a=='number' && typeof b == "number") {
return ascending ? a-b : b-a;
}
else if(typeof a=='string' && typeof b == "string"){
return (ascending ? 1 : -1) * a.localeCompare(b);
}
else {
return 0;
}
}
When you add a movie, you just call sort again. You will need to remember the last sorting parameters for that.
Your sort will work fine. The problem is that after you've sorted you can't just display that movie, you have to redisplay the entire list. You're almost there with your sortByRating method, but it doesn't recreate the entire list correctly. Try something like:
function showMoviesList(element) {
let innerHTML = "";
for (let i = 0; i < movieStorage.length; i++) {
innerHTML += `
<div class="item-title">
<p>${movieStorage[i].title}</p>
</div>
<div class="item-rating">
<p>${movieStorage[i].rating}</p>
</div>
<div class="item-delete">
<i class="fa fa-trash trash-icon delete"></i>
</div>
`;
}
element.innerHTML = innerHTML;
}
This resets the inner HTML of the element to the complete movie list in order every time it's called.
Now call showMoviesList(movieList) instead of calling addMovieToList in sendMovie.
I've been working on a JavaScript code in order to make a checkout cart of a pizza, but have been having an issue with the showCart function.
let pizzas=[
{ name:"Pepperoni", img:"pizza.png", price:8.99},
{ name:"Alfredo", img:"pizza.png", price:9.99},
{ name:"Cheese", img:"cheese.png", price:7.99}
];
function registerButtonEvents()
{
let buttons=document.getElementsByTagName("button");
for(let i = 0; i < buttons.length-1; i++)
{
buttons[i].addEventListener("click", function() {
addToCart(i);
});
}
let number = localStorage.getItem("number");
if(number == null)
number = 0;
document.getElementById("num").innerHTML = number;
}
function addToCart(pId)
{
let cartJ = localStorage.getItem("cart");
let cart;
if(cartJ===null) //Cart is empty
{
cart=[];
}
else
{
cart=cartJ.split(",");
}
cart.push(pId);
let number= localStorage.getItem("number");
if(number===null)
number = 0;
document.getElementById("num").innerHTML = `${++number}`;
localStorage.setItem("cart", cart.toString());
localStorage.setItem("number", number);
}
function clearCart()
{
localStorage.removeItem("cart");
localStorage.removeItem("num");
}
function showCart()
{
let cartJ = localStorage.getItem("cart");
let cart = [];
let info = "";
if(cartJ === null)
{
document.getElementById("myCart").innerHTML=`<h2>No items in cart!</h2>`;
}
else
{
cart = cartJ.split(",");
for (let i in cart)
{
let item = pizzas[cart[i]];
info+=
`<div class="row">
<div class="col-md-2 text-center">
<h3>${item.name}</h3>
</div>
<div class="col-md-2 text-center">
<img class="pizza" src="./images/${item.img}" alt="pepperoni">
</div>
<div class="col-md-2 text-center">
<h3>${item.price}</h3>
</div>
<div class="col-md-2 text-center">
<button type="button" class="btn btn-primary" onclick="removePizza(${i})">Remove</button>
</div>
</div>
`;
}
document.getElementById("myCart").innerHTML=info;
}
}
function removePizza(piz)
{
var cart = localStorage.getItem("cart");
cart = cart.split(",");
cart.splice(piz, 1);
if (cart.length == 0)
clearCart();
else
{
localStorage.setItem("cart", cart);
localStorage.setItem("number",cart.length);
}
showCart();
}
Developer tools tell me that the error is in the line in:
let item = pizzas[cart[i]];
but I don't necessarily understand why. If anyone could send some feedback it would be greatly appreciated.
The problem is when you access <h3>${item.name}</h3>. Your item is undefined there because your cart (cart = cartJ.split(",");) probably stores some strings like "Pepperoni" (as you split them using a comma) and after that you want to access the pizzas array using one of those strings instead of an index.