React.js splice removing wrong item from array list - javascript

I want to remove an item from an array getting the target.id, this app is for a cart, so in other words i want to remove an item from the cart when i click on the bin icon.
<span style={{fontSize:'50px'}}>Basket</span>
<ul style={{listStyle: 'none'}}>
{this.state.clickedNum.map((i) => <li key =
{this.props.gameData.id[i]} value={i}>
{this.props.gameData.gameNames[i]} <br/>
<img src={require('../assets/coins.png')} style={{width:'20px'}}/>
<strong> {this.props.gameData.prices[i]} Gil </strong>
<img src={require('../assets/bin.png')} style={{width:'20px', justifyContent:' flex-end'}} id={this.props.gameData.id[i]} onClick={this.removeClick}/>
<br/>
<hr style={{borderColor:'black'}} />
</li>
</ul>
This is the onClick={this.removeClick} function:
removeClick = (e) => {
e = e.target.id;
let clickedNum = this.state.clickedNum;
let isDisabled = this.state.isDisabled;
console.log("this is i" + e);
clickedNum.splice(e, 1);
isDisabled.splice(e,1);
this.setState({
clickedNum: clickedNum,
isDisabled:isDisabled
})
this.forceUpdate();
}
remove click is binded like this in the constructor function:
this.removeClick = this.removeClick.bind(this);
The problem comes that if you click the bin when there is more than one item in the cart it does not delete the first element and it does not always delete the correct item, however, if there is only one item in the cart it will delete the correct one.
I also note that :
console.log("this is i" + e);
returns the correct value (the id of button in which it was clicked on)

I personally find it stressful to use splice. Why not use filter instead so you'll have something like this.state.clickedNum.filter(num => num.id !== e.target.id)
removeClick = (e) => {
id = e.target.id;
let clickedNum = this.state.clickedNum.filter(num => num.id !==id);
let isDisabled = this.state.filter(num => num.id !==id;
this.setState({
clickedNum: clickedNum,
isDisabled:isDisabled
})
}

Related

How can delivered array in event function on javascript with React?

There is two screen. First picture is show list. If clicked Button which is next to search Button, second picture is showed. Second is select filter. When user select options in filter and clicked "적용" Button, list will be changed.
And there code is here.
...
const [modalOpen, setModalOpen] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(6);
const [area] = useState(location.state.area)
const [city] = useState(location.state.city)
// all list
const locList = restList.filter(
key => (key.address.includes(area) && key.address.includes(city))
);
//about Modal
const openModal = () => {
setModalOpen(true);
}
const closeModal = () => {
setModalOpen(false);
}
...
let target;
let foodList = [[], []]
const sel_Food = (e) => {
if (e.target.tagName === "BUTTON") {
target = e.target.innerText;
if (!foodList.includes(target))
foodList[0].push(target)
} else {
target = e.target.parentNode.nextSibling.innerText;
foodList[1] = target
}
}
//make list
const list = (foodList) => {
let result = [];
if (foodList[0].length === 1) {
result = locList.filter(key => key.foodType.includes(foodList[0][0]))
} else {
for (let i = 0; i < foodList[0].length; i++) {
let tmp = locList.filter(key => key.foodType.includes(foodList[0][i]))
result.push(...tmp)
}
}
if (foodList[1].length != 0) {
result = result.filter(key => key.friendly.includes(foodList[1]))
}
return result
}
return (
<div>
... {
(locList.length === 0)
? ...
: <div>
<div className="btn_class_list">
...
<React.Fragment>
<button className="button_filter" onClick={openModal}><img className="icon_filter" src={icon_filter} alt="icon_filter"/></button>
<Modal_Restaurant open={modalOpen} close={closeModal} header="필터">
<p className="langoption">음식 종류</p>
<div>
...
</div>
<p className="langoption">Halal Standard</p>
<div className="foodtype">
...
</div>
</Modal_Restaurant>
</React.Fragment>
</div>
<Item rlist={currentPosts(locList)} moveTo="restaurant" area={area} city={city}></Item> //make List
<Pagination start={numOfFirst} last={numOfLast} paginate={setCurrentPage}></Pagination>
</div>
}
</div>
)
sel_Food function record option that user selected.
list function make sub list for delivered to Item component.
But I don't know how to delivered array result in list function with "적용" button.
Thank you.
As I understand from the question, you need to change the list of items you display according to the filters the user applies. It can be done with the state. As a start, you can try to update the list of items through a filter function and use the state variable to render the filtered results. You'd asked about returning a value when a button is clicked. Buttons have an onClick handler in React. You can pass it a function like this:
<Button onClick={handleClick} />
or if your function takes any arguments:
<Button onClick={() => handlClick(args)} />

React - Last list element removed when deleting from the middle

I am trying to implement a list composed of an <input> field as well as a delete button, for each item. I also have an Add item button near the list so the user can add new entries.
I am encountering an issue when trying to delete a certain item from the list.
For example:
The initial list
index
input-value
1
a
2
b
3
c
4
d
5
e
After deleting the item at index 3
index
input-value
1
a
2
b
4
c
5
d
As you can observe, the right item is deleted, but the contents are somehow shifted from their initial place and it appears like the last item is always deleted.
I can't figure it out what am I doing wrong.
Here is the parent component:
export default function ListPage() {
const [itemList, setItemList] = useState([]);
const removeItem = (index) => {
console.log(index);
const list = Object.assign([], itemList);
const updatedList = list.filter((object, i) => i != index);
setItemList(updatedList);
console.log(updatedList);
};
const addItem = () => {
const updatedList = [...itemList, <ListElement />];
setItemList(updatedList);
console.log(updatedList);
};
return (
<div className="list-page">
<div className="list-page-title">
<h2>Create your own List</h2>
<br></br>
<h4>Create your own list</h4>
</div>
<input
className="title-input"
type="text"
placeholder="Enter Title"
/>
<div className="list-content">
{itemList.map((data, index) => {
return (
<div>
<ListElement
handleRemove={() => removeItem(index)}
index={data.index}
/>
</div>
);
})}
</div>
<button className="add-button" onClick={addItem}>
<span className="list-page-button-icon">+</span>Add Item
</button>
</div>
);
}
And here is the ListElement component:
export default function ListElement(props) {
return (
<div className="list-item">
<input
className="item-input"
type="text"
placeholder={props.index}
></input>
<MdRemoveCircleOutline
className="remove-button"
onClick={props.handleRemove}
/>
</div>
);
}
Inside your removeItem function, you don't need to do const list = Object.assign([], itemList);; which is messing the order of how the list is stored and rendered.
You already have access to the entire list in the itemList variable you defined before.
So, instead of
const removeItem = (index) => {
console.log(index);
const list = Object.assign([], itemList);
const updatedList = list.filter((object, i) => i != index);
setItemList(updatedList);
console.log(updatedList);
};
So, instead of
const removeItem = (index) => {
const updatedList = itemList.filter((object, i) => i != index);
setItemList(updatedList);
};

remove function deletes wrong items from array

So i am making my to-do app and i have encountered this weird problem where my removeToDo function targets wrong items in weird pattern apart from the very first deleted item(which always is being removed just fine). Let's say we have items in the array with id's from 0 to 6 :
Clicked to remove item with ID = 3 - removed item with ID = 3
Clicked to remove item with ID = 4 - removed item with ID = 5
Clicked to remove item with ID = 5 - removed item with ID = 6
Clicked to remove item with ID = 0 - removed item with ID = 0
Clicked to remove item with ID = 2 - removed item with ID = 4
Clicked to remove item with ID = 1 - removed item with ID = 2
Clicked to remove item with ID = 6 - removed item with ID = 1
So it's not really following an obvious pattern (thought it may be something like id + 1 or something but it doesn't seem like it). Also i did exactly the same test as above for the second time to see if it randomizes, it doesn't, the results were exactly the same.
Here is some code
HTML
<body>
<div class='app'>
<ul id='list'>
</ul>
<div class="footer">
<i class="fas fa-plus-circle" aria-hidden="true" id='addButton'></i>
<input type="text" id='itemInput' placeholder="Add a to-do" />
</div>
</div>
<script src="./app.js"></script>
</body>
JS
const list = document.getElementById("list");
const input = document.getElementById("itemInput");
let id;
//get the item from the local storage
let data = localStorage.getItem('TODO');
//check if data is not empty
if(data) {
LIST = JSON.parse(data)
id = LIST.length; // set the list id to the last in the array
loadList(LIST); // load all the items in the array to the UI
} else {
//if data is empty
LIST = [];
id = 0;
}
function loadList(array) {
array.forEach(item => {
addToDo(item.name, item.id, item.done, item.trash);
})
}
function addToDo(toDo, id, done, trash) {
// if trash is true do not execute the code below
if (trash) {return ;}
const DONE = done ? check : uncheck;
const LINE = done ? lineThrough : "";
const text =`
<li class="item">
<i class="far ${DONE}" id='${id}'></i>
<div class="description ${LINE} wrap">${toDo}</div>
<i class="fas fa-trash-alt" id='${id}'></i>
</li>`;
const position = "beforeend";
list.insertAdjacentHTML(position, text);
}
// remove to-do
function removeToDo(element, i) {
let newList = [...LIST]
element.parentNode.parentNode.removeChild(element.parentNode);
i = newList.indexOf(newList[event.target.id]) //<-- i think that is the problem, the indexing is not working as it should, as a result app gets confused ?
alert(i)
//newList[event.target.id].trash = true;
newList.splice(i, 1);
LIST = newList;
console.log(LIST);
return LIST;
}
// click listener for job complete and job delete
list.addEventListener('click', e => {
const element = e.target;
if(e.target.className == "fas fa-trash-alt" ){
removeToDo(element);
}else if(e.target.className == "far fa-circle") {
jobComplete(element);
}else if(e.target.className == "far fa-check-circle"){
jobComplete(element);
}
}
)
//add a task with "enter" key
document.addEventListener("keyup", (event) => {
if(event.keyCode == 13){
const toDo = input.value;
if(toDo) {
addToDo(toDo, id, false, false);
LIST.push(
{
name: toDo,
id: id,
done: false,
trash: false
}
);
localStorage.setItem('TODO', JSON.stringify(LIST));
id++;
input.value = '';
}
}
})
EDIT :
The items deleted in weird pattern are in the LIST array, actual buttons i click are being deleted just fine. I think i didn't explained that well enough
I think it will be best not to consider the id for removing items.
You can consider the value as well.
Instead of splice(i,1), please try using
newList = newList.filter(function( obj ) {
return obj.name !== element.previousElementSibling.innerHTML;
});
The problem is this:
id = LIST.length; // set the list id to the last in the array
The .length property of an array returns the number of items in the array, but array indexes are zero-based. An array with 5 items in it (length === 5), will have its last item index be 4.
The index of the last item in an array is .length -1.

Why will my local storage not update when i change an item to the trash?

Im just gonna dump my code on here even though i know you're not supposed to. My todo list works pretty well, the only thing that doesn't work is when i hit the delete button it removes the todo from the user interface but doesn't remove it from the local storage. When i hit refresh the deleted item comes back.
//Select Elements
const clear = document.querySelector(".clear");
const dateElement = document.getElementById("date");
const list = document.getElementById("list");
const input = document.getElementById("input");
//Class names for to-do items
const CHECK = "fa-check-circle";
const UNCHECK = "fa-circle-thin";
const LINE_THROUGH = "lineThrough";
//Variables
let LIST;
let id;
//get item from local strorage
let data = localStorage.getItem("Todo");
//check if data is not emplty
if(data){
LIST = JSON.parse(data);
id = LIST.length;// set the id to the last item in the list
loadList(LIST); //load the list to the user interface
} else{
LIST = [];
id = 0;
};
// load items to user interface
function loadList(array){
array.forEach(function(item){
addToDo(item.name, item.id, item.false, item.delete);
});
};
//clear the local storage
clear.addEventListener("click", function(){
localStorage.clear();
location.reload();
});
//add item to local strorage
//let variable = localStorage.setItem('key');
//localStorage.setItem("Todo", JSON.stringify(LIST));
//show todays date
let options = {weekday : 'long', month:'short', day:'numeric'};
let today = new Date();
dateElement.innerHTML = today.toLocaleDateString("en-US", options);
// create a function that will add the to-do to the list when entered
function addToDo(todo, id, done, trash){
if(trash){return;};
const DONE = done ? CHECK : UNCHECK;
const LINE = done ? LINE_THROUGH : "";
const item = `
<li class="item">
<i class="fa ${DONE} co" job="complete" id="${id}"></i>
<p class="text ${LINE}">${todo}</p>
<i class="fa fa-trash-o de" job="delete" id="${id}"></i>
</li>
`;
const position = "beforeend";
list.insertAdjacentHTML(position, item);
};
//make the input become a todo item when the enter key is pressed
document.addEventListener("keyup", function(event){
if(event.keyCode == 13){
const todo = input.value;
if(todo){
addToDo(todo, id, false, false);
LIST.push({
name : todo,
id : id,
done : false,
trash : false,
});
localStorage.setItem("Todo", JSON.stringify(LIST));
id++;
}
input.value = "";
}
});
//make the todo item change to completed when the user clicks on it
function completeToDo(element){
element.classList.toggle(CHECK);
element.classList.toggle(UNCHECK);
element.parentNode.querySelector(".text").classList.toggle(LINE_THROUGH);
LIST[element.id].done = LIST[element.id].done ? false : true;
};
//remove a todo from the LIST
function removeToDo(element){
element.parentNode.parentNode.removeChild(element.parentNode);
LIST[element.id].trash = true;
};
//target the created items
list.addEventListener("click", function(event){
let element = event.target;// return clicked element inside the list
const elementJOB = element.attributes.job.value;// complete or delete
if(elementJOB == "complete"){
completeToDo(element);
} else if (elementJOB == "delete"){
removeToDo(element);
}
localStorage.setItem("Todo", JSON.stringify(LIST));
});
In removeToDo you set trash to true, but when loading the list you look for the key named delete.
Then, in addToDo you check if the 4th param (trash) if it is truthy, but you pass the value of item.delete which is undefined, so it is falsy.
You need to change this addToDo(item.name, item.id, item.false, item.delete); in this addToDo(item.name, item.id, item.false, item.trash);

Remove selection when clicking on another list item

I'm mapping an array of objects as shown below
<div>
{categoryArray.map(category => <DFCard category={category} key={category.id}/>)}
</div>
DFCard
<div className="cat_div" id={category.id} onClick={() => this.selectCategory(category.id)}>
<i className={`${category.icon} fontawesome vertical_center setting_icon`}/>
<span className="cat_lbl vertical_center">{category.name}</span>
{this.state.selectedId === category.id && 'selected'}
</div>
selectCategory(id) {
this.setState({
selectedId: id
})
}
I'm trying to show a selected on the item i'm clicking on. My approach does not make the selected label to remove when clicking on another list item. How can i fix this issue?
try this
selectCategory(id) {
let oldSelected = this.setState.selectedId;
oldSelected.push(id)
this.setState({selectedId: oldSelected})
}
{this.state.selectedId && this.state.selectedId.indexOf(category.id) > -1 && 'selected'}

Categories