deleting an item from array in React with unique id - javascript

I am a newbie and trying to delete an item from array by clicking a button.
However, I could not retrieve the id I want.
All I could get from e.target was the "input" itself, not the whole item, let alone the id.
//some other stuff
deleteDrink = (event) => {
console.log(event.target)
}
return(
//blahblahblah[enter image description here][1]
orders.map((order, i) => (
<Order
key={orders[i].id}
drink={orders[i].drink}
price={orders[i].price}
quantities={orders[i].number}
note={orders[i].note}
deleteDrink={this.deleteDrink}
/>
) ```
When I clicked the button, all I can get is:
<input class="delete-button br4 w-10 grow" type="button" value="Delete"></input>
what should I do to retrieve the id?
[1]: https://i.stack.imgur.com/KM7Ng.jpg

Instead of setting the handler to this.deleteDrink, set a handler which calls deleteDrink with the ID (or index) of the element to be deleted:
deleteDrink={() => { this.deleteDrink(order.id); }}
deleteDrink = (id) => {
console.log('deleting', id)
}
To delete the particular order when deleteDrink is called, perhaps you'd want something like this:
deleteDrink={() => { this.deleteDrink(i); }}
// Example if you're using hooks:
deleteDrink = (i) => {
setOrders([
...orders.slice(0, i),
...orders.slice(i + 1)
]);
}

Related

onClick handler in React is triggered by adjacent element , not by element which it was meant to trigger

const ProductScreen = () => {
const [qty, setQty] = useState(0);
const handleAddtoCart = () => {
console.log(qty);
};
return (
<div className="productScreen">
{product.countInStock > 0 && (
<div className="productScreen__details__qty">
<span>Qty : </span>
<select
id="qty"
name="qty"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</select>
</div>
)}
{product.countInStock > 0 ? (
<div className="productScreen__details__price__details__cart">
<button
className="productScreen__details__price__details__toCart"
onClick={handleAddtoCart()}
>
Add to Cart
</button>
</div>
</div>
</div>
);
};
Here handleAddtoCart gets triggered when selecting options but doesnt trigger when button is pressed(handleAddtoCart is added to button), when I change handleAddtoCart() to handleAddtoCart in onClick attribute of button it works properly.
Why when handleAddtoCart() is given as onclick attribute it is getting triggered by adjacent select option and is not getting triggered when button is pressed
You need to make a callback to that function, because every render of the component, will literally execute handleAddtoCart() and not as you expect it to happen only of the onClick trigger.
as react's Offical documents explained:
To save typing and avoid the confusing behavior of this, we will use the arrow function syntax for event handlers here and further below:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => console.log('click')}>
{this.props.value}
</button>
);
}
}
Notice how with onClick={() => console.log('click')}, we’re passing a function as the onClick prop. React will only call this function after a click. Forgetting () => and writing onClick={console.log('click')} is a common mistake, and would fire every time the component re-renders.
for more details:
https://reactjs.org/tutorial/tutorial.html
Change
onClick={handleAddtoCart()}
by
onClick={handleAddtoCart}
Also try with :
onChange={(e) => setQty(e.currentTarget.value)}
instead of :
onChange={(e) => setQty(e.target.value)}
The currentTarget read-only property of the Event interface identifies
the current target for the event, as the event traverses the DOM. It
always refers to the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

addEventListener for only one time on any one element in forEach loop javascript

I have an array of NodeList. I loop through every NodeList element and add click event Listener.
var itemsList = document.querySelectorAll('.items');
itemList.forEach(item => {
item.addEventListener('click', () => {
console.log('clicked');
})
})
As soon as I clicked any one of the items I want to remove the event listener for all the other items as well.
It doesn't matter each item is clicked or not.
To do it directly without jQuery or anything, and without overcomplicating it, you could do something like this:
const itemsList = document.querySelectorAll('.items');
const onClick = () => {
console.log('clicked');
itemsList.forEach(item => {
item.removeEventListener('click', onClick);
});
};
itemsList.forEach(item => {
item.addEventListener('click', onClick);
});
Basically you keep a reference to the click function, and the function itself removes itself from all nodes in the list.
If you want to know which item was clicked, you can add a parameter to the onClick function, which will be the click event, from which you can get the item that was clicked, like so:
const itemsList = document.querySelectorAll('.items');
const onClick = event => {
const clickedItem = event.target
console.log('clicked on ' + clickedItem.textContent);
itemsList.forEach(item => {
item.removeEventListener('click', onClick);
});
};
itemsList.forEach(item => {
item.addEventListener('click', onClick);
});
Something along these lines will let you get a reference to which item was actually clicked.
This is very concise using jquery
var handler=function(){
//your logic of click event
alert('clicked')
}
// handle click and add class
$('.items').on("click", function(){
handler();
$('.items').not(this).off("click");
})
This will removes every other click events after clicking the first one. If you want to remove every event including the first clicked, then remove the not() method from my code
One approach is to add the listener to an ancestor of your elements i.e. document + a target check on which element was clicked, if you need to remove this listener you only have to remove it once
function handleClick(event) {
if (event.target.classList.contains("items")) {
alert(event.target.textContent)
document.removeEventListener('click', handleClick)
}
}
document.addEventListener('click', handleClick);
<div id="app">
<li class="items">1</li>
<li class="items">2</li>
<li class="items">3</li>
<li class="items">4</li>
<li class="items">5</li>
</div>
You can make this more expressive
var itemsList = document.querySelectorAll('.items');
const updateClickListener = (list, callback, operation = 'add') => {
itemList.forEach(item => {
item[`${operation}EventListener`]('click', () => {
callback();
updateClickListener(list, () => {}, 'remove');
})
})
}
updateClickListener(
list,
() => {
console..log('clicked');
});

React - event.target returns the innerText of the previously clicked element instead of the currently clicked element

I created a drop down menu that returns a selected option through an event handler when the option is clicked.
When I click on the option, I target the innerText of that option via event. It looks like this: event.target.innerText. The selected targets value is then used to fill in an 'input' to show the users selected value. Exactly how you expect a <select> input to work. The targets value is also used for filtering listed components, but that is not what I am worried about here.
When the drop down menu component loads, inside of a componentDidMount() method, the state is updated with a default value so that the drop down menus load with the first option pre-populated (this is so that they are not empty before a user selects an option).
When I click on an option to make a selection, the returned event.target.innerText is of the previous selection. So if option 1 was the default value when the component mounts, and then I select option 2 and console.log the result, the value would be option 1. If I then select another option, option 3, the returned console.log() would be option 2. It's one behind.
In this .gif, you can see that when componentDidMount() fires, it console.log()s the default values of the drop down menu. But when I make a selection, you'll notice the console.log() is only returning the event.target.innerText of the previously selected option.
Here is the component:
class DropDownSelect extends Component {
constructor(props) {
const { inputOptions } = props;
const { option1 } = inputOptions;
super(props);
this.state = {
showOptions: false,
selectionMade: option1
};
}
setShowOptions = () => {
const { showOptions } = this.state;
this.setState(prevState => ({ showOptions: !prevState.showOptions }));
};
setSelectionMade = event => {
const { target } = event;
event.stopPropagation();
this.setShowOptions();
this.setState({ selectionMade: target.innerText });
console.log(this.state.selectionMade);
};
setDefaultSelectionOnLoad = () => {
const { inputOptions } = this.props;
this.setState({ selectionMade: inputOptions.option1 });
};
componentDidMount() {
this.setDefaultSelectionOnLoad();
console.log(this.state.selectionMade);
}
render() {
const { showOptions, selectionMade } = this.state;
const { inputOptions } = this.props;
const inputOptionsArray = Object.keys(inputOptions);
return (
<DropDownSelectMenu>
<DropDownSelectPlaceholder onClick={this.setShowOptions}>
<p>{selectionMade}</p>
<i>
<FontAwesomeIcon icon={faCaretDown} />
</i>
</DropDownSelectPlaceholder>
{showOptions ? (
<DropDownSelectOptions>
{inputOptionsArray.map((key, index) => {
return (
<DropDownOption
onClick={event => {
this.setSelectionMade(event);
}}
key={index}
>
{inputOptions[key]}
</DropDownOption>
);
})}
</DropDownSelectOptions>
) : null}
</DropDownSelectMenu>
);
}
}
The DropDownOption styled component is where the function that updates the selection in the state is added as an onClick handler. Since this component is a child, and you need to click the parent component to open the DropDownOption component, I thought that maybe the event handler was bubbling up and grabbing the event.target value from the parent, so I added event.stopPropagation() to the event handler function setSelectionMade(). This didn't do anything for me.
Your code works fine, only this debugging method fails ;)
This is of the most common errors in react - expecting state update immediatelly just after setState call.
Read docs, please. Value can be read in setState callback.
You can simply console.log(selectionMade) in render (before return () to get current value.

How to setState on click event, only once within a loop?

I have a function where I am looping through a list of labels.
I have a onClick event where I am calling a function.
This function sets the state for clicked to that of the id of the clicked item in the loop. The function also console.log's the state.
It's logging the state of clicked 8 times. There are current 4 items in my loop.
How can I make it so that I can set the state to clicked every time the user clicks on an item in the list?
Here is my loop:
{
filteredArray.map(link => {
return (
<div
key={link.id}
role="button"
style={{paddingBottom: 20}}
onClick={this.changeView(link.id)}
onKeyPress={this.changeView(link.id)}
tabIndex={0}
>
<Paragraph size="large">
<a className='heading__dropdown__link'
{link.label}
</a>
</Paragraph>
</div>
)
})
}
Here is my function changeView:
changeView(id) {
const { clicked } = this.state
console.log(clicked)
return (
() => this.setState({clicked: id})
)
}
Your calling the function for every element, set your function like so:
changeView = id => ev => this.setState({clicked: id});
remove onPress and add arrow function in onClick like this
onClick={()=>this.changeView(link.id)}
hope this will help

react - setting input prop based on input name

I have a checkbox input:
import { Checkbox } from 'semantic-ui-react';
<Checkbox
checked={false}
ref={id}
/>
Now I would like to write a function that set this checkbox's checked to true (the onClick function goes on another React element, not the checkbox itself):
onClick: (id) => {
//Find the correct checkbox, set the prop
this.refs[id].checked = true;
}
But I have no idea how to do it (the above code does nothing). How do I find react components based on a certain prop?
Maintain a state object that has mapping of id to checkbox state and then onClick based on the id change the state
this.state = {
checked: {'12': true. '23':false}
}
<Checkbox
checked={this.state.checked[id]}
/>
If you want to toggle
onClick = (id) => {
var checked = {...this.state.checked}
checked[id] = !this.state.checked[id];
this.setState({checked})
}
If you only want to set
onClick = (id) => {
var checked = {...this.state.checked}
checked[id] = true;
this.setState({checked})
}
You have to add an onClick attribute in the Checkbox and the funciton name.
Inside the on click function you should get as parameter the event
and check the evet.target.checked
which is the checkbox's attribute to show clicked status.
You don't need to use refs if its all in the same component.
Let me know if you have trouble
You could do something like:
<Checkbox
checked={false}
ref={id}
onClick={() => { this.onClick(id); }}
/>
Not sure if this Checkbox is rendered in the same component tho, so the reference to this might be wrong.
onClick: (id) => {
this.refs[id].checked = true;
}

Categories