I'm making favorite buttons that saves them with localStorage in a different page. I added those favorite buttons to every paragraph. I don't want to write a lots of same codes for each of them. The question is that, is there any way to make same buttons work independently and save their parent objects to another page. So far I've made just one favorite button to one paragraph and I've managed to save it to a different page. Here's my code:
<form action="pages/login_screen.html">
<p>A<span class="heart"><i class="fa fa-heart-o" aria-hidden="true"></i></span></p>
<p>B<!--<span class="heart"><i class="fa fa-heart-o" aria-hidden="true"></i></span>--></p>
<p>C<!--<span class="heart"><i class="fa fa-heart-o" aria-hidden="true"></i></span>--></p>
<p>D<!--<span class="heart"><i class="fa fa-heart-o" aria-hidden="true"></i></span>--></p>
<p>E<!--<span class="heart"><i class="fa fa-heart-o" aria-hidden="true"></i></span>--></p>
<script>
$(window).on('load',function(){
if(localStorage.toggled != "with_toggle"){
$(".heart").html('<i class="fa fa-heart" aria-hidden="true"></i>');
}else{
$(".heart").html('<i class="fa fa-heart-o" aria-hidden="true"></i>');
}
});
$('.heart').toggleClass(localStorage.toggled);
$('.heart').on('click',function(){
if (localStorage.toggled != "with_toggle") {
$(".heart").html('<i class="fa fa-heart-o" aria-hidden="true"></i>');
$('.heart').toggleClass("with_toggle", true);
localStorage.toggled = "with_toggle";
localStorage.removeItem("paragraphValue");
} else {
$(".heart").html('<i class="fa fa-heart" aria-hidden="true"></i>');
$('.heart').toggleClass("with_toggle", false);
localStorage.toggled = "";
var paragraph = document.querySelector(".heart").parentNode.innerHTML;
localStorage.setItem("paragraphValue", paragraph);
return false;
}
});
</script>
<form action="pages/login_screen.html">
Here's the second page:
<div id="favorites"><!--FAVORITES HERE--></div>
<script>
document.getElementById("favorites").innerHTML = localStorage.getItem("paragraphValue");
</script>
You need to save the likes in an array and save the array
NOTE I remove the span and added the class to the <i>
https://jsfiddle.net/mplungjan/c8zf07rh/
$(function() {
const swapToggle = ($heart, toggle) => {
$heart.toggleClass("fa-heart-o", toggle);
$heart.toggleClass("fa-heart", !toggle);
};
const $hearts = $(".heart");
const toggleString = localStorage.getItem("toggles");
console.log(toggleString)
const toggles = toggleString ? JSON.parse(toggleString) : $hearts.map(function() {
return $(this).hasClass('fa-heart')
}).get(); // get all hearts on page
$hearts.each(function(i, elem) { // initialise from localStorage
swapToggle($(this), toggles[i])
$(this).data("idx", i); // save position in array
})
$('.heart').on('click', function() {
const idx = +$(this).data("idx"); // position in array
toggles[idx] = !toggles[idx]; // actual toggling
swapToggle($(this), toggles[idx])
localStorage.setItem("toggles", JSON.stringify(toggles))
})
});
Related
I'm making a task board project.
Must say I'm using only HTML, CSS, JS, and nothing else right now.
I'm making a fade-in effect to the newly added note (ul element), and I would like to delete the fade-in class from the previously added note.
this is a chunk of my code that displays the note inside the div.
function displayAllTasks(allTasks){
taskNotesDiv.innerHTML = "";
for(const task of allTasks){
const index = allTasks.indexOf(task);
const note = `
<div class"noteDiv">
<ul class="fadeInNote">
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>
</ul>
</div>
`
taskNotesDiv.innerHTML += note;
}
}
I tried already another function to delete it but with no success.
any help would be appreciated!
There can be multiple approaches, but my approach is to create element using document.createElement . The modified JS will become:
function displayAllTasks(allTasks) {
last_ul = null; // store the last ul element added
taskNotesDiv.innerHTML = "";
for (const task of allTasks) {
const index = allTasks.indexOf(task);
let noteDiv = document.createElement('div');
noteDiv.classList.add('noteDiv');
note_ul = document.createElement('ul');
note_ul.classList.add('fadeInNote');
note_ul.innerHTML = `
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>`
noteDiv.appendChild(note_ul);
// if it is not the first element, then remove the class from previous
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
last_ul = note_ul; // this becomes previous for next iteration
taskNotesDiv.appendChild(noteDiv);
}
// remove class of the last element
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
}
I create the elements in HTML variable, using a btn click , then it is appended to a div. After that , i cant get any interaction with the elements cretated. I really want to do it without Jquery.
btnAdd.addEventListener("click", (e) => {
e.preventDefault();
if (input.value === "") {
alert("Insert.text")
} else {
store.push(input.value);
counter += 1
let createDivList = document.createElement("div");
createDivList.classList.add("list")
const Html =
`<div class="text">
<h5>${input.value}</h5>
</div>
<div class="icons">
<span class="btn-done icon"><i class="far fa-check-circle"></i></i></span>
<span class="btn-editar icon"><i class="far fa-edit"></i></span>
<span class="btn-recliclar icon"><i class="far fa-trash-alt"></i></span>
</div>
`;
createDivList.innerHTML = Html;
todoList.appendChild(createDivList)
input.value = "";
}
})
remove.forEach((button) => {
button.addEventListener("click", () => {
alert("hello")
})
});
const cartContent = document.querySelector(".cart_content");
.
.
.
addCartItem(item) {
const div = document.createElement('div');
div.classList.add('cart_item');
div.innerHTML = `
<div class="shop_cart_items_wrapper">
<span class="remove_item" data-id=${item.id}><i class="fas fa-times"></i></span>
<div class="shop_cart_items">
<p class="item_amount">${item.amount}</p>
<span class="cart_title_text_wrapper"><h4 class="cart_title_text">${item.title}</h4></span>
<span class="cart_price_amount_wrapper"><h5 class="cart_price_amount">$${item.price}</h5></span>
</div>
<div>
<div class="inc_dec_amounts_cart">
<i class="fas fa-chevron-up" data-id=${item.id}></i>
<i class="fas fa-chevron-down" data-id=${item.id}></i>
</div>
</div>
</div>`;
cartContent.appendChild(div);
}
.
.
.
cartContent.addEventListener("click", event => {
if (event.target.classList.contains("remove_item")) {
let removeItem = event.target;
let id = removeItem.dataset.id;
cartContent.removeChild.firstElementChild(removeItem.parentElement.parentElement);
this.removeItem(id);
}
So I have everything that's needed for the code to work. I want the entire product item removed from the cart as I press the 'times' icon. I think the removeItem.parentElement.parentElement is not targetting the times icon. What do I have to do to make it target the times icon and close the cart_item div?
It sounds like you're trying to remove the item relative to where the class remove_item is defined (which I assume is maybe the X icon or something. A better way of going about is just defining an id on the parent item itself, finding that element via document.querySelector, and then removing it.
So instead of having something like this
const div = document.createElement('div');
div.classList.add('cart_item');
div.setAttribute('data-item-id', item.id); // <-- now the cart_item has an id associated to it
div.innerHTML = `
<div class="shop_cart_items_wrapper">
<span class="remove_item" data-id=${item.id}><i class="fas fa-times"></i></span>
<div class="shop_cart_items">
And then your remove function becomes
cartContent.addEventListener("click", event => {
if (event.target.classList.contains("remove_item")) {
let removeItem = event.target;
let id = removeItem.dataset.id;
cartContent.removeChild(document.querySelector(`[data-item-id=${id}`));
this.removeItem(id);
}
Or something of the sort. If you're looking for a specific answer on how to get this relatively via your method, that's possible but just giving you another way of going about the solution.
so i made a div with a icon, and when the user clicks the icon the id of a movie is pushed in the local storage. So when the user refresh the page i want that the icon to remain a full heart and not an empty heart. How could i do that?
var favorites = JSON.parse(localStorage.getItem('favorites')) || [];
// add class 'fav' to each favorite
const whiteHeart = 'fa fa-heart-o fa-2x';
const blackHeart = 'fa fa-heart fa-2x';
const button = document.querySelector('#heart_icon');
$('#heart').click(function() {
const movie_id = $(this).attr('data-id');
index = favorites.indexOf(movie_id);
if (!movie_id) return;
// item is not favorite
if (index == -1) {
favorites.push(movie_id);
button.className = blackHeart;
// item is already favorite
} else {
favorites.splice(index, 1);
button.className = whiteHeart;
}
// store array in local storage
JSON.parse(localStorage.setItem('favorites', JSON.stringify(favorites)));
})
<div id="heart" data-id="ID1"> <i id="heart_icon" class="fa fa-heart-o fa-2x"></i> </div>
Please note that if you have more than one heart, you need to use a class
$('.heart').click(function() {
In your current code you need to
Change
JSON.parse(localStorage.setItem('favorites', JSON.stringify(favorites)) to just localStorage.setItem('favorites', JSON.stringify(favorites))
onload run over stored favs
Suggested code https://plungjan.name/SO/heartslocalstorage.html
let favorites;
const toggleIcon = ($icon, id) => {
const isFav = favorites.indexOf(id) !== -1; // or includes for non-IE11 (polyfill on my site)
$icon
.toggleClass("fa-heart-o", !isFav)
.toggleClass("fa-heart", isFav); // swap classes
};
$(function() {
favorites = JSON.parse(localStorage.getItem('favorites')) || [];
$('.heart').on("click", function() {
const id = $(this).attr('data-id');
const $icon = $(this).find("i");
if (favorites.indexOf(id) === -1) favorites.push(id); // save the movie
else {
const index = favorites.indexOf(id); // get the movie position
favorites.splice(index, 1); // and delete it from favourites
}
toggleIcon($icon, id);
// store array in local storage
localStorage.setItem('favorites', JSON.stringify(favorites));
})
$('.heart[data-id]').each(function() { // set the classes on ALL hearts
const id = $(this).data("id");
const $icon = $(this).find("i");
toggleIcon($icon, id);
});
});
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div class="heart" data-id="ID1"> <i id="heart_icon" class="fa fa-heart-o fa-2x"></i> </div>
<div class="heart" data-id="ID2"> <i id="heart_icon" class="fa fa-heart-o fa-2x"></i> </div>
<div class="heart" data-id="ID3"> <i id="heart_icon" class="fa fa-heart-o fa-2x"></i> </div>
I know this question seems like a repeat, but I've waded through many similar questions and have had no success.
I am working with a financial reporter and want to make negative balances red and positive balances green.
Here is my current jQuery. When I debug in the browser, the entire function gets skipped. Yet for some reason, my classes are ALL getting changed to text-dang.
$('.balance').each(function (i) {
var content = $(this).text().replace('$', '');
var balance = parseInt(content, 10);
if (balance <= 0)
{
$('.balance').removeClass("text-succ").addClass("text-dang");
}
else {
$('.balance').removeClass("text-dang").addClass("text-succ");
}
});
I have also tried it without the wrapping function - $('.balance').each(function (i) { - but then only the FIRST element with class .balance was selected.
Here is my HTML. (Note that I am using Razor, and iterating through multiple accounts which will all contain this h2. The balances were coming in just fine until I used the wrapping function.)
<h2>
<strong>#account.Name</strong>
<i class="fa fa-angle-right"></i>
Balance: <span class="balance text-succ">$ #account.Balance</span>
</h2>
I'm pretty new to Javascript and StackOverflow so please let me know if you need more information. Any help is appreciated!
The problem is that you're updating all elements on each iteration. You need to use this to select the current element.
$('.balance').each(function(i) {
var $this = $(this);
var content = $this.text().replace('$', '');
var balance = parseInt(content, 10);
if (balance <= 0) {
$this.removeClass("text-succ").addClass("text-dang");
} else {
$this.removeClass("text-dang").addClass("text-succ");
}
});
.text-succ {
color: green;
}
.text-dang {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<h2><strong>Account1</strong> <i class="fa fa-angle-right"></i> Balance: <span class="balance text-succ">-4</span></h2>
<h2><strong>Account2</strong> <i class="fa fa-angle-right"></i> Balance: <span class="balance">-2</span></h2>
<h2><strong>Account3</strong> <i class="fa fa-angle-right"></i> Balance: <span class="balance">0</span></h2>
<h2><strong>Account4</strong> <i class="fa fa-angle-right"></i> Balance: <span class="balance">2</span></h2>
<h2><strong>Account5</strong> <i class="fa fa-angle-right"></i> Balance: <span class="balance">4</span></h2>
You need to apply and remove class to the referred element, in this case $(this) instead of $('.balance').
Check this fiddle
$('.balance').each(function(){
var balance = parseInt($(this).text().replace('$',''), 10);
$(this).removeClass("text-dang").addClass("text-succ");
if (balance <= 0)
$(this).removeClass("text-succ").addClass("text-dang");
});
remember you are looping through all elements... when $('.balance').each loops call the anonymous function and uses $(this) to refer to the $(".balance") element that is object of the iteration...
$('.balance').each(function (i) {
var content = $(this).text().replace('$', '');
var balance = parseInt(content, 10);
if (balance <= 0)
{
$(this).removeClass("text-succ").addClass("text-dang");
}
else {
$(this).removeClass("text-dang").addClass("text-succ");
}});
There is a toogleClass that could take two parameters, one the string for the class and the second one a logic test... so you could do something like:
$('.balance').each(function (i) {
var content = $(this).text().replace('$', '');
var balance = parseInt(content, 10);
//to be on the safe side:
$(this).removeClass();// or $(this).removeClass("text-dang text-succ");
$(this).toggleClass("text-dang", balance <= 0);
$(this).toggleClass("text-succ", balance > 0);
});
Well is just an idea...