So basically I have a Grocery List and an Inventory List. I want to be able to:
Add an item to either list.
Remove an item from either list.
Move an item from one list to the other.
Each list has its own array, and when you "Add an item" to either list, I have a function (nodeConstructor) that pushes the item to its corresponding array and builds an 'item element' in the desired div (the grocery list or inventory list).
The problem that I'm having is in moving an item from one list to the other. When you click the 'move' button, my 'nodeConstructor' function is supposed to be called and it should basically recreate the selected element in the other list. It kind of does that, except the item value (inputVal) renders as 'undefined' in the div rather than the value of the item that was moved (however it moves from array to array correctly).
The other problem is that moving an item from the Grocery List to the Inventory List correctly splices the item from the Grocery List array and pushes it to the Inventory List array, but moving an item from the Inventory List to the Grocery List neither splices the item from the array nor moves it to the Grocery List array (I'm thinking it has something to do with the order of conditionals being checked but I'm not sure).
If anyone could show me where I'm going wrong it would be greatly appreciated. Also, any suggestions on an easier way to achieve this functionality would be welcomed.
Here is a link to the Codepen that demonstrates my issue: https://codepen.io/TOOTCODER/pen/OJXQKGp?editors=1011
HTML
<label for="groceryInput">Add Grocery Item: </label>
<input id="groceryInput" type="text">
<button id="groceryInputBtn">Submit</button>
<label for="inventoryInput">Add Inventory Item: </label>
<input id="inventoryInput" type="text">
<input id="inventoryInputBtn" type="submit">
<div class="outputDiv" id="arr1Output"><h1>Grocery</h1></div>
<div class="outputDiv" id="arr2Output"><h1>Inventory</h1></div>
CSS
.outputDiv{
width: 200px;
height: 200px;
border: 1px solid black;
margin: 25px 0 0 25px;
}
.outputDiv h1{
text-align: center;
text-decoration: underline;
}
JavaScript
const groceryInput = document.querySelector("#groceryInput");
const groceryInputBtn = document.querySelector("#groceryInputBtn");
const inventoryInput = document.querySelector("#inventoryInput");
const inventoryInputBtn = document.querySelector("#inventoryInputBtn");
const arr1Output = document.querySelector("#arr1Output");
const arr2Output = document.querySelector("#arr2Output");
const groceryList = [];
const inventoryList = [];
//add grocery item
groceryInputBtn.addEventListener("click", function(){
nodeConstructor(groceryInput, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan")});
arr1Output.addEventListener("click", controlBtns);
//add inventory item
inventoryInputBtn.addEventListener("click", function(){
nodeConstructor(inventoryInput, inventoryList, arr2Output, "newInventoryItemDiv",
"newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan")});
arr2Output.addEventListener("click", controlBtns);
//item element builder
function nodeConstructor(inputVal, list, output, divClass,itmClass, deleteClass, moveClass){
const newItmDiv = document.createElement("div");
newItmDiv.classList.add(divClass);
const newItm = document.createElement("span");
newItm.classList.add("itmClass");
const deleteBtnSpan = document.createElement("span");
deleteBtnSpan.innerHTML = "<i class='far fa-trash-alt'></i>";
deleteBtnSpan.classList.add(deleteClass);
const moveBtnSpan = document.createElement("span");
moveBtnSpan.innerHTML = "<i class='fas fa-exchange-alt'></i>";
moveBtnSpan.classList.add(moveClass);
list.push(inputVal.value);
for(let i=0;i<list.length;i++){
newItm.innerText = list[i];
}
newItmDiv.appendChild(newItm);
newItmDiv.appendChild(deleteBtnSpan);
newItmDiv.appendChild(moveBtnSpan);
output.appendChild(newItmDiv);
};
//delete and move buttons
function controlBtns(event){
const clicked = event.target;
for(let i=0;i<groceryList.length;i++){
//grocery delete btn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryDeleteBtnSpan"){
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//grocery move btn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryMoveBtnSpan"){
nodeConstructor(groceryList[i], inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
inventoryList.push(groceryList[i]);
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
}
//inventory delete btn
for(let i=0;i<inventoryList.length;i++){
if(clicked.parentElement.parentElement.innerText==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryDeleteBtnSpan"){
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//inventory move btn
if(clicked.parentElement.parentElement.value==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryMoveBtnSpan"){
nodeConstructor(inventoryList[i], groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
groceryList.push(inventoryList[i]);
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
}
console.log("InventoryList: "+inventoryList);
console.log("GroceryList: "+groceryList);
}
Hey so the below code will at least work with the switching, the issue you had is you were not calling the nodeConstructor in the move button and since your lists only contain the value, nothing was being updated.
So what I did was updated nodeConstructor to take both input value and value of the item you are moving with this line const nodeValue = typeof inputVal === 'object' ? inputVal.value : inputVal
Then in the move functions I updated both move functions. I grabbed the old value before I delete it from the list, then I call the nodeContructor so both the lists are updated with the value.
const groceryVal = groceryList[i]
groceryList.splice(i,1);
nodeConstructor(groceryVal, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
In terms of of what you could be doing. I think you could probably add a click event to the move buttons that update their own position so you dont have to have that big function.
const groceryInput = document.querySelector("#groceryInput");
const groceryInputBtn = document.querySelector("#groceryInputBtn");
const arr1Output = document.querySelector("#arr1Output");
const inventoryInput = document.querySelector("#inventoryInput");
const inventoryInputBtn = document.querySelector("#inventoryInputBtn");
const arr2Output = document.querySelector("#arr2Output");
const groceryList = [];
const inventoryList = [];
let nodeList = [];
groceryInputBtn.addEventListener("click", function(){
nodeConstructor(groceryInput, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
});
arr1Output.addEventListener("click", controlBtns);
inventoryInputBtn.addEventListener("click", function(){
nodeConstructor(inventoryInput, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
});
arr2Output.addEventListener("click", controlBtns);
function nodeConstructor(inputVal, list, output, divClass,itmClass, deleteClass, moveClass){
const newItmDiv = document.createElement("div");
newItmDiv.classList.add(divClass);
const newItm = document.createElement("span");
newItm.classList.add("itmClass");
const deleteBtnSpan = document.createElement("span");
deleteBtnSpan.innerHTML = "<i class='far fa-trash-alt'></i>";
deleteBtnSpan.classList.add(deleteClass);
const moveBtnSpan = document.createElement("span");
moveBtnSpan.innerHTML = "<i class='fas fa-exchange-alt'></i>";
moveBtnSpan.classList.add(moveClass);
const nodeValue = typeof inputVal === 'object' ? inputVal.value :
inputVal
list.push(nodeValue);
for(let i=0;i<list.length;i++){
newItm.innerText = list[i];
}
newItmDiv.appendChild(newItm);
newItmDiv.appendChild(deleteBtnSpan);
newItmDiv.appendChild(moveBtnSpan);
output.appendChild(newItmDiv);
};
function controlBtns(event){
const clicked = event.target;
for(let i=0;i<groceryList.length;i++){
//groceryDeleteBtn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryDeleteBtnSpan"){
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//groceryMoveBtn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryMoveBtnSpan"){
const groceryVal = groceryList[i]
groceryList.splice(i,1);
nodeConstructor(groceryVal, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
}
}
for(let i=0;i<inventoryList.length;i++){
//inventoryDeleteBtn
if(clicked.parentElement.parentElement.innerText==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryDeleteBtnSpan"){
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//inventoryMoveBtn
if(clicked.parentElement.parentElement.innerText==inventoryList[i] && clicked.parentElement.classList[0]=="inventoryMoveBtnSpan"){
const inventoryVal= inventoryList[i]
inventoryList.splice(i,1);
nodeConstructor(inventoryVal, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
}
}
console.log("InventoryList: "+inventoryList);
console.log("GroceryList: "+groceryList);
}
Related
I am a newbie at web development. I am trying to display data that is being stored in javascript array, inside an unordered list as list elements.
I have tried looping through the elements in the array and display them one at a time using for loops but its not working
let linksArray = [] // array to store link leads while browsing
let inputEl = document.getElementById("input-el") // to get a hold on the input element from the dom
let displayEl = document.getElementById("display_link-el")
//function to save links inputs into linksArray
function save(params) {
linksArray.push(inputEl.value)
console.log(linksArray);
localStorage.setItem("mylinks", JSON.stringify(linksArray))
inputEl.value = ""
displayEl.textContent = linksArray
}
//function to conver linksArray to a list element in the DOM
function convetToListli(linksArray) {
for (let i = 0; i < linksArray.length; i++) {
let links = "<li>"
linksArray[i]
" </li>"
}
}
<input id="input-el" title="lead" placeholder="input weblink" type="text">
<button id="input-btn" onclick="save()">SAVE </button>
<button id="del-btn" ondblclick="delLeads()">DELETE</button>
<div>
<div>
<ul id="display_link-el"></ul>
</div>
<div>
<ul id="log_link-el"></ul>
</div>
</div>
I have added small correction to your script
function save(params) {
linksArray.push(inputEl.value)
console.log(linksArray);
inputEl.value=""
displayEl.innerHTML = convetToListli(linksArray)
}
//function to conver linksArray to a list element in the DOM
function convetToListli(linksArray) {
var links = ""
for (let i = 0; i < linksArray.length; i++) {
links= links + "<li>"+linksArray[i]+" </li>"
}
return links
}
This is just for example purchase
NOTE: Make sure to filter the input field while using innerHTML because it will leads to XSS
You should learn basic DOM manipulations. Here's one possible solution for your question
const list = document.querySelector('.list');
const links = ['link 1', 'link 2', 'link 3'];
links.forEach(link => {
let item = document.createElement('li');
item.textContent = link;
list.appendChild(item)
})
<ul class="list"></ul>
I am storing the todo-items on an array of objects. I want to map the array to get the HTML elements. I am able to do this using innerHTML but I want to do it with createElement.
I am expecting <li><span>TEXT</span></li> output but I am getting only span. It seems append is not working.
HTML code :
<div class="todo">
<h1>Todo</h1>
<form name="todo--form">
<input type="text" name="todo--input" />
<button
type="submit"
name="todo--submit"
class="p-2 bg-slate-500 rounded"
>
Add
</button>
</form>
<ul class="todo--list"></ul>
</div>
JS Code :
const addTodoForm = document.querySelector(`[name="todo--form"]`);
const todoList = document.querySelector('.todo--list');
const todos = [];
// function getLabel() {}
function handleSubmit(e) {
e.preventDefault();
const text = this.querySelector(`[name="todo--input"]`).value;
const item = {
text: text,
finished: false,
};
if (text) {
todos.push(item);
addTodoForm.reset();
const todoItems = todos.map((todo, i) => {
let newSpan = document.createElement('span');
let newLi = document.createElement('li');
newSpan.textContent = todo.text;
let newEl = newLi.append(newSpan);
return newEl;
});
console.log(todoItems);
todoList.append(...todoItems);
}
return;
}
addTodoForm.addEventListener('submit', handleSubmit);
I am getting only <span><span> as output.
When the <form> is submitted there's only one item being appended to list at a time so there's no need to build a one item array. BTW event handlers (functions that are bound to an event) don't return values like a normal function can, but there are indirect ways to get values from them (like from your OP code, that array outside of the function pushing objects).
Details are commented in example
// Reference <form>
const form = document.forms.todo;
// Reference <ul>
const list = document.querySelector('.list');
// Define array for storage
let tasks = [];
// Bind "submit" event to <form>
form.onsubmit = handleSubmit;
// Event handlers passes Event Object by default
function handleSubmit(e) {
// Stop default behavior during a "submit"
e.preventDefault();
// Reference all form controls
const IO = this.elements;
/*
Define {item}
Add current timestamp to object {item}
Add <input> text to {item}
Add {item} to [tasks]
Clear <input>
*/
let item = {};
item.log = Date.now();
item.task = IO.data.value;
tasks.push(item);
IO.data.value = '';
/*
Create <time>
Assign timestamp <time>
Convert timestamp into a readable date and time
Add formatted datetime as text to <time>
*/
const log = document.createElement('time');
log.datetime = item.log;
let date = new Date(item.log);
log.textContent = date.toLocaleString();
/*
Create <output>
Add text of <input> to <output>
*/
const txt = document.createElement('output');
txt.value = item.task;
/*
Create <button>
Add type, class, and the text: "Delete" to <button>
*/
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'delete';
btn.textContent = 'Delete';
// Create <li>
const li = document.createElement('li');
// Append like crazy
li.append(log);
li.append(txt);
li.append(btn);
list.append(li);
console.log(tasks);
}
html {
font: 300 2ch/1.2 'Segoe UI';
}
input,
button {
font: inherit;
}
output {
display: inline-block;
margin: 0 8px 8px;
}
button {
cursor: pointer;
}
.as-console-row::after {
width: 0;
font-size: 0;
}
.as-console-row-code {
width: 100%;
word-break: break-word;
}
.as-console-wrapper {
max-height: 30% !important;
max-width: 100%;
}
<form id='todo'>
<fieldset>
<legend>ToDo List</legend>
<input id='data' type="text" required>
<button class="p-2 bg-slate-500 rounded">Add</button>
<ul class="list"></ul>
</fieldset>
</form>
const todoItems = todos.map((todo, i) => {
let newSpan = document.createElement('span');
let newLi = document.createElement('li');
newSpan.textContent = todo.text;
let newEl = newLi.append(newSpan);
return newLi;
});
In this block of code, I believe the newEl variable being created isn't correct. Try changing newLi.append(newSpan) to newLi.appendChild(newSpan)
This is also listed below
if (text) {
todos.push(item);
addTodoForm.reset();
const todoItems = todos.map((todo, i) => {
let newSpan = document.createElement('span');
let newLi = document.createElement('li');
newSpan.textContent = todo.text;
let newEl = newLi.appendChild(newSpan);
return newEl;
});
console.log(todoItems);
todoList.append(...todoItems);
}
return;
Thanks for all the answers.
Upon reading on the documentation of append and appendChild, it seems elements cannot be saved into a variable upon using these methods.
I just need to return the append li element.
const todoItems = todos.map((todo, i) => {
let newSpan = document.createElement('span');
let newLi = document.createElement('li');
newLi.setAttribute('data-index', i);
const todoTextNode = document.createTextNode(todo.text);
newSpan.appendChild(todoTextNode);
newLi.appendChild(newSpan);
return newLi;
});
I was making a simple to-do list. You submit itens from an input and they go to the To-DO section. When you click over them they go to the 'Done' section. And when you click on them again, they vanish forever. It was all working fine.
But I realized the doneItens array kept growing in length, which I wanted to optimize. So I came up with this line of code
doneItens.splice(i, 1);
which goes inside an onclick event, which you can see in the code inside the deleteDone function.
That gives the error, though,
Error:{
"message": "Uncaught TypeError: doneItens.splice is not a function"
If I put it outside and below the onclick event it also doesn't work. How can I do it?
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i]);
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
const doneItens = document.getElementsByClassName('feito');
console.log('done length', doneItens.length)
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
doneItens[i].style.display = 'none';
doneItens.splice(i, 1);
}
}
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>
With the use of JavaScript DOM API such as Node.removeChild(), Element.remove() and Node.parentNode, your task can be solved with this code:
const input = document.getElementById('play');
const todo = document.getElementById('todo');
const done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
// create new "todo" item
const newTodo = document.createElement('li');
newTodo.textContent = input.value;
todo.append(newTodo);
// clean the input field
input.value = '';
// listen to "click" event on the created item to move it to "done" section
newTodo.addEventListener('click', moveToDone);
}
function moveToDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', moveToDone);
// move clicked todo-element to "done" section
const newDone = event.target.parentNode.removeChild(event.target);
done.append(newDone);
// listen to "click" event on the moved item to then completely delete it
newDone.addEventListener('click', removeFromDone);
debugElementsLeak();
}
function removeFromDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', removeFromDone);
// complete remove clicked element from the DOM
event.target.remove();
debugElementsLeak();
}
function debugElementsLeak() {
const todoCount = todo.childElementCount;
const doneCount = done.childElementCount;
console.log({ todoCount, doneCount });
}
<div id="flex">
<form class="form" onsubmit="handleSubmit(event)">
<input placeholder="New item" type="text" id="play">
<button>Add item</button>
</form>
<div id="left">
<h1>To-do:</h1>
<p class="instruction"><em>(Click over to mark as done)</em></p>
<ol id="todo"></ol>
</div>
<div id="right">
<h1>Done:</h1>
<p class="instruction"><em>(Click over to delete it)</em></p>
<p id="placeholder"></p>
<ol id="done"></ol>
</div>
</div>
You'll want to use splice,
and then rather than use hidden, 'refresh' the done element by adding all elements in the spliced array.
I've commented my code where I've made changes and why
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i].cloneNode(true));
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
var doneItens = document.getElementsByClassName('feito');
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
var splicedArray = spliceFromArray(doneItens,doneItens[i]);// NEW BIT -CALL NEW SPLICE FUNCTION
done.innerHTML=""; // NEW BIT - SET OVERALL DONE TO BLANK ON DELETE
for(var index in splicedArray){// NEW BIT - fOR EACH RETURNED ELEMENT IN THE SPLICE, ADD IT TO THE OVERALL DONE ELEMENT
done.appendChild(splicedArray[index]);
}
}
}
}
function spliceFromArray(arrayInput,element){// NEW BIT - SPLICE FUNCTION THAT RETURNS SPLICED ARRAY
var array = Array.from(arrayInput);
var index = array.indexOf(element);
if(index!=-1){
if(array.length==1 && index == 0){
array = [];
}
else{
array.splice(index,1);
}
}
return array;
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>
edited with all the code, sorry for my messy coding, I am begginer
hope you can help with this,
I have just created a button in the dom with a function, I gave the button a class to apply an event listener, for some reason i am not able to activate the listener, does anyone have a clue about what I am doing wrong?
//this is th initial array of items, after I am changing it to an arrayof objects
let shoppingList = ['banana','apples','cherries','oranges', 'peaches'];
const list = document.querySelector('.list');
//this is the last thing I need, create new items and allow the del button
const foo=()=>{
console.log('hi');
}
const adder =(item, index, price,name)=>{
list.innerHTML += `<div class='item${[index+1]}'>${name}, price ${price} </div>`;
item[index]= {name,price};
const delElm = document.createElement('button');//the element to remove items
delElm.className = 'remove';
delElm.innerHTML = 'X';
list.appendChild(delElm);
const btndel = document.querySelector('.remove')
console.log(btndel)
btndel.addEventListener('click', foo)
}
//assign a random price to the original array
for (let i = 0; i < shoppingList.length; i++) {
let prices = i+Math.round((((Math.random()*5)+10))*100)/100;
let name = shoppingList[i];
adder(shoppingList,i,prices,name);
}
const btnElm= document.querySelector('.press');
//function to add new elements
const addItm=()=>{
const nameElm = document.querySelector('#text');
const priceElm = document.querySelector('#price');
let name = nameElm.value;
let prices = Number(priceElm.value);
let i = shoppingList.length-1;
adder(shoppingList, i, prices,name)
console.log(shoppingList)
}
console.log(shoppingList)
btnElm.addEventListener('click', addItm)
edit with the HTML, basically, the user can add new items filling the form, each item should be posible to be removed,
<input type="text" id="text" placeholder="name item">
<input type="text" id="price" placeholder="price">
<button class="press">add</button> -->
thanks you in advance
I am trying to create a 'favourites' system where the user can click on a star in the top right of a button to add that course to their list of 'favourites'. Here is the HTML for said button (there are 6 of them and all 6 are the same):
<button class="divflexbuttonitem">
<div class="libraryfaviconcontainer">
<i class="libraryfavicon" onclick="toggleFavourite()"></i>
</div>
</button>
And here is my (attempt at) JavaScript for the toggleFavourite() function:
function toggleFavourite() {
console.log("Running toggleFavourite();");
var favicon = document.getElementsByClassName("libraryfavicon");
var faviconCount = favicon.length;
var favArray = new Array();
var favArrayString = favArray.toString();
var i;
for(i = 0; i < faviconCount; i++) {
favArray.push(favicon[i].id);
}
alert(favArray.length);
alert(favArrayString);
let favourite = false;
if (favicon[i].style.backgroundImage == 'url("libraryfavselected.png")') {
favourite = true;
}
else if (favicon[i].style.backgroundImage == 'url("libraryfavunselected.png")') {
favourite = false;
}
if (!favourite) {
favicon[i].style.backgroundImage = 'url("libraryfavselected.png")';
console.log("Added to Favourites");
}
else {
favicon[i].style.backgroundImage = 'url("libraryfavunselected.png")';
console.log("Removed from Favourites");
}
}
I am trying to get all elements with a specific class name, add them to an array, and call them from an array to change the url of the 'favicon' of the specific favicon that was pressed. However, my code does not work whatsoever and i am lost as to how to correctly code it.
There are better ways to structure this type of application, but here is some really simple code to get you started.
You can see that the fav class is toggled on and off when an item is clicked, and then we can get all the current favourites by querying all elements with the fav class.
const toggleFavourite = (event) => {
if (event.target){
const clickTarget = event.target;
clickTarget.classList.toggle('fav')
}
}
//Example use, get all favs and attach the text as a new element
const getFavs = () => {
const favs = document.querySelectorAll('.fav');
const favContainer = document.querySelector('.favs')
favContainer.innerHTML = "";
for( let fav of favs){
let newFav = document.createElement('div');
newFav.textContent = fav.textContent;
favContainer.appendChild(newFav)
}
}
.fav {
color: red;
}
<i class="" onclick="toggleFavourite(event)">1</i>
<i class="" onclick="toggleFavourite(event)">2</i>
<i class="" onclick="toggleFavourite(event)">3</i>
<i class="" onclick="toggleFavourite(event)">4</i>
<i class="" onclick="toggleFavourite(event)">5</i>
<button id="getFavs" onclick="getFavs()">Get Favs</button>
<section class='favs'>
</section>