How to handle click on specific button in loop? - javascript

I have created following design:
Here is the react js code:
{this.props.BetSlipDataObj.betDetails.data.map(
(value, index) => {
<div className="d-flex justify-content-end">
<button
className="info-button"
data-toggle="collapse"
href="#collapseExample"
role="button"
aria-expanded="false"
aria-controls="collapseExample"
// onClick={
// value.betId != null
// ? _this.getBetIdDetails(value.betId)
// : value.childId != null
// ? _this.getBetIdDetails(value.childId)
// : ""
// }
>
</div>
})}
Here I am trying following task
If I click on one button it should expand the box
But if I click on one button all boxes are expanding.
If I call some method on click its getting called infinitely
Can someone help me to correct the code ?

You can call a function on button click. I think it was calling infinitely because you were not passing a reference to the function.
{this.props.BetSlipDataObj.betDetails.data.map(
(value, index) => (
<div className="d-flex justify-content-end" key={index}>
<button
className="info-button"
data-toggle="collapse"
href="#collapseExample"
role="button"
aria-expanded="false"
aria-controls="collapseExample"
onClick={
value.betId != null
? () => _this.getBetIdDetails(value.betId)
: value.childId != null
? () => _this.getBetIdDetails(value.childId)
: () => {}
}
>
</div>
)
)}
You were also missing the key prop on div
EDIT:
One button is opening all the boxes because they all have the same IDs and controls.
To make the IDs and controls unique, you can do something like this:
{this.props.BetSlipDataObj.betDetails.data.map(
(value, index) => (
<div className="d-flex justify-content-end" key={index}>
<button
className="info-button"
data-toggle={`collapse${index}`}
href={`#collapseExample${index}`}
role="button"
aria-expanded="false"
aria-controls={`collapseExample${index}`}
onClick={
value.betId != null
? () => _this.getBetIdDetails(value.betId)
: value.childId != null
? () => _this.getBetIdDetails(value.childId)
: () => {}
}
>
</div>
)
)}

The solution seems pretty straightforward. You're directly executing a function in the onClick. That's why all of them are getting executed. You just need to change the onClick as follows:
onClick = { () => {
if(value.betId != null){
_this.getBetIdDetails(value.betId)
} else if (value.childId != null){
_this.getBetIdDetails(value.childId)
} else {return ""} }

To each div you need to give unique id, may be primary key of that row, and when that button is clicked pass the id to the opening function, and append that to id of that div to open. Hope it helps. This will go like this:-
onclick=handler(1)
div id should be like this:- open1, open2
handler should be like this:-
handler(id) => idofelement+id open

Related

Get key of mapped child component from parent function

I have a child navigation component and i'm trying to get the key of the selected item in the parent component to update my state to the selected nav item. I'm using a map in the child component and I cant seem to pass the key of the selected item back up to the parent item to set the state. here are my components
Parent
** my function to set the nav item **
let navPress = async key => {
let selNavItem = await navItems.find(object => {
return object.key === key
});
setActiveNavItem(selNavItem.key)
}
** return for parent component **
return(
<ProjectDetailNav
navItems={navItems}
activeNavItem={activeNavItem}
onClick={() => navPress}
/>
)
Child component (nav) with map function
<div id='nav-container'>
{props.navItems.map(navItem => {
if (navItem.key === props.activeNavItem) {
// console.log(navItem.key)
return (
<button className='active-nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
} else {
return (
<button className='nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
}
})}
</div >
By onClick={props.onClick(navItem.key)} you are assigning the return value of props.onClick to buttons click event calling it immediately on render. It should be wrapped in a function.
<button
className="active-nav-item"
key={navItem.key}
onClick={() => props.onClick(navItem.key)}
>
<img className="nav-item-icon" src={navItem.icon} />
<h6 className="nav-item-title">{navItem.title}</h6>
</button>
This way when onClick event is fired, the anonymous function will be called which will call props.onClick(navItem.key).

Remove item from array with click function

I have a Todo react app, where when you click on checkbox, the selected item is stored in an array, and displayed in a separate div where there is cross icon. I wanted to remove the displayed item in my second div when clicked on cross icon.
Below is my code:
const [list1, setList1] = useState([]);
const pushHandler1 = (data) => {
let newArr = [];
if (!list1.includes(data)) {
newArr = [...list1, data];
setList1(newArr)
console.log("put: ", newArr);
}
else {
newArr = list1.filter((id) => id !== data);
setList1(newArr)
console.log("pull", newArr);
}
}
<div id="listBox1">
<Checkbox
defaultChecked={false}
color="primary"
inputProps={{ 'aria-label': 'secondary checkbox' }}
onChange={(e) => pushHandler1(e.target.name)} name="Language1"
/>
<label>Language1</label>
</div>
<div id="listBox2">
{
list1.length > 0 &&
<div className='checkList'>
{
list1 && list1.length > 0 &&
list1.map((ele, index) => {
return (
<div key={index} className="listItemDiv">
<p>{ele}</p>
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1(e.target.name)} name="Language1"></i>
</div>
)
})
}
</div>
}
</div>
But instead of deleting this item, it creates a new empty div in my second Div. I am new to JavaScript and react js and not able to figure what I am doing wrong.
NOTE
Thank you for the answer:
changing the onClick in this way onClick={(e) => pushHandler1(ele)} helped me in solving the issue.
But now there is one more issue. When I cancel the selected item, my checkbox is still checked(true). So if now I uncheck it, it displays the unchecked item in my second div. Is there a way to also uncheck the checkbox, when cancelling the selected item?
i elements don't have a name attribute, and so they don't have the name reflected property that input and other elements have.
Since you're already creating a function for the click handler, you don't need to put an attribute on the i, just put the value directly in the handler:
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1("Language1")}></i>
That said, hardcoding the value doesn't look right. It seems like that should be ele, not "Language1":
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1(ele)}></i>

Disable onClick event with JSON data

I want to disable a button click using a parameter from a JSON file:
JSON Parameter
"reactJson": {
"disable:"true"
}
My current onClick method works fine but if the parameter is true, I want to disable the onClick event. Currently my code looks like this:
let myJsonParam = reactJson.disabled //default is false
onClick
<button
onClick={() => {
handleSumbit();
}}
>
Exit and Save
</button>;
I know I can do this if it were a boolean:
{
!myJsonParam ? (
<button
onClick={() => {
handleSumbit();
}}
>
Exit and Save
</button>
) : (
<button
onClick={() => {
}}
>
Exit and Save
</button>
);
}
But since it is a string in JSON trueis there a different way to disable the button when the string is changed in JSON instead of replicating it and removing the onClick event ?
How do you think of this solution?
<button
onClick={() => {
if (!myJsonParam)
handleSumbit();
}}
>
Exit and Save
</button>

React Typescript - Show hidden Divs not currently showing

I have an array that contains Title1, Title2, Title3, all the way to Title8. If that item is not empty I want to display with it's corresponding information. Currently that works.
However I want to add a button that will allow me to display all fields. For example let's say Title1 through Title3 is not null. It will show that (which it currently does). I want to add a button that when clicked will display all Titles 1-8.
Here is my current code. In the code below I'm only showing 4 if statements and removed all content to save space:
{ this.state.showExtraRows? <div>
{ this.state.Product[0].Title1 ?
<div>
//Display some fields here
</div>
: null
}
{ this.state.Product[0].Title2 ?
<div>
//Display some fields here
</div>
: null
}
{ this.state.Product[0].Title3 ?
<div>
//Display some fields here
</div>
: null
}
{ this.state.Product[0].Title4 ?
<div>
//Display some fields here
</div>
: null
}
</div>
: null
}
<button className={styles.btn}
type="button"
onClick={()=>{this.setState({showExtraRows:!this.state.showExtraRows})}}>
{ this.state.showExtraRows? 'Hide Rows' : 'Show Rows'}
</button>
I'm not too sure if I'm supposed to wrap the whole thing in the this.state.showExtraRows? statement.
I think it's better to use a map function here
const productWithTitles = this.state.Product.filter((Product) => !!Product.title);
return (
<div>
{this.state.showExtraRows && (
<div>
{productWithTitles.slice(0, 3).map((product) => {
return (
<div>
//Display some fields here
</div>
);
})}
</div>
)}
</div>
);

Having multiple buttons call a function in ReactJS

Sorry if the title is vague. My problem is that I have three button tags, and for each tag I want it to send a unique argument to selectSupplier(). However no matter what button I press selectSupplier() only receives the last value ("ultramar") as an argument.
selectSupplier(supplier){
this.props.Obj.supplier = supplier
}
render() {
//console.log("SUPPLIER", this.props)
return (
<div>
<button onClick={this.showMenu}>
Select Supplier
</button>
{
this.state.showMenu
? (
<div
className="menu"
ref={(element) => {
this.dropdownMenu = element;
}}
>
<button value="Husky" onClick={this.selectSupplier("Husky")}> Husky </button>
<button value="Shell" onClick={this.selectSupplier("Shell")}> Shell </button>
<button value="Ultramar" onClick={this.selectSupplier("Ultramar")}> Ultramar</button>
</div>
)
: (
null
)
}
</div>
);
You can call like this :
this.selectSupplier.bind(this,"Husky");

Categories

Resources