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>
Related
I am a new learning JS. Who can help me complete this code. I have 2 problem:
render child Node user Chat when click without duplicate
how to remove child Node user when close chat window
full code is here: Jsfiddle
// event handling when click
handleEvents: function () {
let _this = this;
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
_this.renderUserChat(userIndex);
const getChatWithItems = document.querySelectorAll(".chat-with__item");
getChatWithItems.forEach(item => {
item.onclick = function(e){
const itemNode = e.target.closest(".chat-with__top i");
if(itemNode){
chatWithList.removeChild(chatWithItem);
}
}
})
}
}
},
//render user chat with someone
renderUserChat: function (num) {
// console.log(userIndex);
chatWithItem = document.createElement("li");
chatWithItem.classList.add("chat-with__item");
chatWithItem.setAttribute('user-num', num);
chatWithItem.innerHTML = `
<div class="chat-with__top">
<div class="chat-with__img">
<img src="${this.users[num].img}" alt="${this.users[num].name}">
<span class="user__status ${this.users[num].status}"></span>
</div>
<p class="chat-with__name">${this.users[num].name}</p>
<i class="fa-solid fa-xmark"></i>
</div>
<div class="chat-with__body">
<ul class="chat__text">
<li class="chat-text__user">Hey. 👋</li>
<li class="chat-text__user user__chatting">I am here</li>
<li class="chat-text__user user__chatting">What's going on?</li>
<li class="chat-text__user">Have you finished the "project 2" yet?</li>
<li class="chat-text__user user__chatting">I have been fixed bugs</li>
<li class="chat-text__user">OK.</li>
</ul>
</div>
<div class="chat-width__footer">
<i class="fa-solid fa-image"></i>
<i class="fa-solid fa-folder"></i>
<div class="chat-width__input">
<input type="text" id="send-sms" name="send SMS" placeholder="...">
</div>
<i class="fa-solid fa-paper-plane-top"></i>
</div>
`
chatWithList.appendChild(chatWithItem);
},
<ul class="chat-with__list">
</ul>
I have not still known how to solve it, up to now
Just keep track which chat windows are opened in an object.
To give you basic idea of the concept:
// storage for opened chat windows
// this variable must be accessible by event handlers
const openedChats = {};
In chat opened event handler:
if (openedChats[userId]) //check if chat already opened
return;
const chatWithItem = document.createElement("li");
...
openedChats[userId] = chatWithItem; //store window
chatWithList.appendChild(chatWithItem); //show window
In chat close event handler:
const chatWithItem = openedChats[userId]; // get opened chat
if (chatWithItem)
{
chatWithItem.parentNode.removeChild(chatWithItem); // destroy window
delete openedChats[userId]; // remove window
}
If you need to get list of all userIds that have opened chat windows, use:
const openedChatsIds = Object.keys(openedChats);
Finnaly I find the way to code. This is my way
handleEvents: function () {
let _this = this;
let currentChat = [];
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
// get value 'userIndex' for currentChat array
function getCurrentChat(arr, index) {
arr.push(index);
}
// check value userIndex in a currentChat array
function checkCurrentChat(arr, index) {
if (arr.indexOf(index) < 0) {
getCurrentChat(currentChat, userIndex);
return true;
} else {
return false;
}
}
let isExisted = checkCurrentChat(currentChat, userIndex);
// console.log(isExisted);
if (isExisted) {
_this.renderUserChat(userIndex);
}
const getChatWithItems = chatWithList.querySelectorAll(".chat-with__item");
getChatWithItems.forEach( function(item) {
item.onclick = function (e) {
const closeChat = e.target.closest(".chat-with__top i");
if(closeChat){
const getNum = Number(closeChat.parentElement.getAttribute("user-num"));
chatWithList.removeChild(item);
const findNum = currentChat.indexOf(getNum);
currentChat.splice(findNum, 1);
}
}
})
}
}
}
inside, i add an attribute to get number (userIndex):
<div class="chat-with__top" user-num ="${num}">
if you use second .parentElement, it will ok.
closeChat.parentElement.parentElement.getAttribute("user-num")
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'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))
})
});
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")
})
});
I have this code and on Tab click, it is working fine, but I can't change tab from button click.
var tabs = document.getElementById('icetab-container').children;
var tabcontents = document.getElementById('icetab-content').children;
var myFunction = function () {
var tabchange = this.mynum;
for (var int = 0; int < tabcontents.length; int++) {
tabcontents[int].className = ' tabcontent';
tabs[int].className = ' icetab';
}
tabcontents[tabchange].classList.add('tab-active');
this.classList.add('current-tab');
}
for (var index = 0; index < tabs.length; index++) {
tabs[index].mynum = index;
tabs[index].addEventListener('click', myFunction, false);
}
I tried this code :
function changeView() {
tabs[1].click(); // and
tabs[1].addEventListener('click', myFunction, false);
}
What is the right way to do it?
This is the HTML code :
<div class="codepen-container">
<div id="icetab-container">
<div class="icetab current-tab">Add Group <i class="fa fa-users" aria-hidden="true"></i></div>
<div class="icetab">Add User <i class="fa fa-user" aria-hidden="true"></i></div>
</div>
<div class="col-md-offset-8 col-md-4 ">
<button type="button" onclick="changeView()" Text="Save"class="btn btn-default" />
</div>
What you are doing now is adding a new click event listener fot the tab with 1 index, so user still need to click on it to get it working.
You just need to call the myFunction with providing this with setting this.mynum to the index you want to be selected
function changeView() {
myFunction.call({mynum: 1});
}
More readable is:
function changeView(index) {
myFunction.call({mynum: index});
}
and you can call:
changeView(0) for the first tab
changeView(1) for second tab
...