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)} />
Related
So I'm practising react with a simple task master app, where I add each user input as a new task in an array of tasks. In the app, I have Add, Delete, and Update buttons.
Everything seems to be working fine except for the update function, it updates the last index of the array instead of the specific index I clicked.
Here is my JSX
const JsxElement = task.map((eachTask, index) => {
return (
<Fragment key={index}>
<div key={index} className="table-data-container">
<div className="item-data">{eachTask}</div>
<div className="item-data">{date}</div>
<div className="item-data">
<div className="btn-data-container">
<div className="btn-data">
<div className="btn" onClick={() => deleteTask(index)}>Delete</div>
</div>
<div className="btn-data">
<div className="btn" onClick={() => UpdateTaskBtn(eachTask, index)}>Update</div>
</div>
</div>
</div>
</div>
<br/>
{task.length - 1 === index &&
<div className="input-update-container">
<div className="input-area">
<input
ref={inputRef}
type="text"
/>
</div>
<div className="btn-update-add-container">
{update ?
<div className="btn-add" onClick={() => handleTaskUpdate(eachTask, index)}>Update
Task</div>
:
<div className="btn-add" onClick={handleTask}>Add Task</div>
}
</div>
</div>
}
</Fragment>
)
})
The first update button function prepares the input, sets the task to be updated and makes the update button visible. The second one is where I want the update action to happen once clicked.
function UpdateTaskBtn(eachTask) {
inputRef.current.value = eachTask
setUpdate(true)
}
function handleTaskUpdate(e, index) {
const list = [...task]
list[index] = inputRef.current.value
setTask(list)
inputRef.current.value = ""
setUpdate(false)
}
I want to be able to set the task to the specific index I want to update.
based on this line of code
{task.length - 1 === index &&
you are checking if the index is the last index , so you are passing the last index to the handleTaskUpdate function. so you can define a updateIndex state
const [updateIndex,setUpdateIndex] = useState()
then your function should look like this
function UpdateTaskBtn(eachTask,index) {
inputRef.current.value = eachTask
setUpdateIndex(index)
setUpdate(true)
}
function handleTaskUpdate(e, index) {
const list = [...task]
list[updateIndex] = inputRef.current.value
setTask(list)
inputRef.current.value = ""
setUpdate(false)
}
do not forget to pass index to UpdateTaskBtn function in onClick event
Try this
function handleTaskUpdate(e, index) {
const value = inputRef.current.value
const updatedTasks = task.map((task, i) => i === index ? value : task)
setTask(updatedTasks)
inputRef.current.value = ""
setUpdate(false)
}
I am trying to build todo list and I like to put on button(.cancel-task) action which remove exactly item which connected with that button, but when I try to put addEventListener I meet error like "its not a function". Please explain me how to make it with using attribute id which I add before for tasks and also how to remove this item from local storage. Thank you, for your attention.
const taskList = document.querySelector(".todo_tasks-wrapper");
const formTodo = document.querySelector(".control");
const inputTask = document.querySelector(".todo_input");
const btnDeleteTask = document.querySelectorAll(".cancel-task");
const taskKeeper = [];
let taskIdCounter = 0;
const data = JSON.parse(localStorage.getItem("tasks"));
const updateHtml = (taskObj) => {
const newLi = document.createElement("li");
newLi.innerHTML = `<li id="${taskObj.id}" class="item-task">
<span>${taskObj.task}</span>
<button class="cancel-task">
<img src="assets/todo-cancel.png" alt="Cancel">
</button>
</li>`;
taskList.append(newLi);
}
const newTask = (info) => {
taskIdCounter += 1;
const taskObj = {
task: info,
id: taskIdCounter,
};
taskKeeper.push(taskObj);
localStorage.setItem("tasks", JSON.stringify(taskKeeper));
updateHtml(taskObj);
};
formTodo.addEventListener("submit", event => {
event.preventDefault();
const info = inputTask.value.trim();
if(info.length !== 0) {
newTask(info);
inputTask.value = "";
inputTask.focus();
}
});
if(data !== null) {
for(let item of data) {
updateHtml(item);
}
}
<div class="todo_wrapper">
<ul class="todo_tasks-wrapper">
</ul>
<form class="control" action="">
<label class="todo_label-form" for="task">
<input class="todo_input" id="task" type="text" placeholder="Enter new task" maxlength="30">
<input class="todo_submit" type="submit" value="+">
</label>
</form>
</div>
You can use a onclick listener on the todo_tasks-wrapper element and check every element inside the event path to match the criterias.
Example:
todoTaskWrapper.addEventListener("click", (event) => {
for (let el of event.composedPath()) {
// window and document have no matches function, but they are included in the path
if (el.matches && el.matches("button.cancel-task")) {
console.log(el, "is the button clicked")
console.log(el.parentNode, "is the li element");
// remove it
el.parentNode.remove();
}
}
});
MDN: Event.composedPath()
MDN: Element.matches()
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);
};
I have input feild which takes a input (interest) from user and after hitting the Enter key adds the interest to the interests array. Then the elements in this array are displayed on screen via the Domain component as the user goes on adding. The Domain component contains an icon X (cross) which on click should delete the selected/clicked element from the array. Right now the last element in the array is getting removed after clicking.
How can I resolve this? Here is the code:
function Demo() {
const [interest, setinterest] = useState("");
const [interests, setinterests] = useState([]);
const domainSelection = (e) => {
if (e.key === "Enter" && interest.length > 0) {
setinterests((interests) => [...interests, interest]);
setinterest("");
}
};
const RemoveDomain = (e) => {
var arr = [...interests];
var index = arr.indexOf(e.target.value);
arr.splice(index, 1);
setinterests(arr);
};
const Domain = ({ interest }) => {
return (
<span>
{interest}
<span>
<X onClick={RemoveDomain} />
</span>
</span>
);
};
return (
<div>
<Input
name="intersts"
type="text"
placeholder="eg Machine Learning .. "
value={interest}
required={true}
onChange={(e) => setinterest(e.target.value)}
className="interest-input inputs"
onKeyDown={domainSelection}
/>
{interests.map((interest, i) => (
<Domain
interest={interest}
// Prevent duplicate keys by appending index:
key={interest + i}
/>
))}
</div>
);
}
export default Demo;
I think e.target.value is undefined.
Use Filter, This might help
const RemoveDomain = (value) => {
var arr = interests.filter((item) => item !== value);
setinterests(arr);
};
const Domain = ({ interest }) => {
return (
<span>
{interest}
<span>
<X onClick={() => RemoveDomain(interest)} />
</span>
</span>
);
};
I'm having some issues updating a select tag value. When I click on it and try changing the value it logs the new value to the console, but it's value is not changing no matter how many times I click a different option. But when I make some changes in the code editor and save it it display the new value but if I try againg changing the value clicking on it it does not change.
const quantityChange = (e) => {
console.log('changing quantity')
const newCart = shoppingCart
console.log(
"new cart variable created. It's value is " + JSON.stringify(newCart)
)
const index = e.target.dataset.index
console.log('Item index is ' + index)
newCart[index]['quantity'] = e.target.value
console.log(
'The new quantity for the item is ' + newCart[index]['quantity']
)
setShoppingCart(newCart)
console.log(
'new value set for shopping cart. ' +
JSON.stringify(shoppingCart)
)
}
const ShoppingCart = ({ shoppingCart, quantityChange, removeFromCart }) => {
const onSubmit = (e) => {
e.preventDefault()
}
if (shoppingCart.length === 0) {
return <div>There's no items in the shopping cart</div>
}
const options = []
for (let i = 0; i <= 10; i++) {
options.push(
<option name="quantity-1" value={i} key={'qsfkajlf' + i}>
{i}
</option>
)
}
return (
<div>
<h1>
There's {shoppingCart.length} item{shoppingCart.length > 1 && 's'} in
your shopping cart.
</h1>
{shoppingCart.map((item, index) => {
const { id, name, price, image, quantity } = item
return (
<div key={id}>
<div className="flex-container">
<div className="img-container">
<img src={image} alt="" />
</div>
<div className="item-info">
<h2>{name}</h2>
<p>${price}</p>
</div>
<div className="remove-quantity">
<div className="quantity">
<form onSubmit={onSubmit}>
{/* TODO: don't allow more than 10 items */}
<select
id="quantity"
data-index={index}
onChange={quantityChange}
value={quantity}
>
{options}
</select>
</form>
</div>
<div className="remove-container">
<button data-remove={index} onClick={removeFromCart}>
x
</button>
</div>
</div>
</div>
</div>
)
})}
</div>
)
}
It isn't updating because you are doing this:
const quantityChange = (e) => {
console.log('changing quantity')
const newCart = shoppingCart // <-- copy a reference to shoppingCart
// do stuff
setShoppingCart(newCart) // <-- write the original (modified) object back in
}
As the object reference doesn't change, the re-render isn't triggered.
Instead, you just need to copy your object (instead of just copying the reference):
const quantityChange = (e) => {
console.log('changing quantity')
const newCart = {...shoppingCart} // <-- copy the contents into a new object