I have an array of objects, and for each one I .map it into a component called Card.js. Each card has an 'edit' button, and I have an edit form which I want to appear ONLY for the card on which I clicked the button.
At the moment, whatever I try to do to pass an id into the Editform.js component, it still makes the form appear for all of the card components.
Here's the current component I call which is meant to render just form for the clicked button. I pass in all of the cards in the 'cards' array, and what I believe is the id of the current .map object from the calling function:
function Editform({ cards, setCards, id }) {
const thisCard = cards.filter((card) => card.id === id)[0];
const editThisCard = thisCard.id === id; // trying to match id of passed card to correct card in 'cards' array.
console.log(editThisCard);
return (
<>
{editThisCard && ( // should only render if editThisCard is true.
<div className="form">
<p>Name of game:</p>
<input type="text" value={thisCard.gamename}></input>
<p>Max players: </p>
<input type="text" value={thisCard.maxplayers}></input>
<p>Free spaces: </p>
<input type="text" value={thisCard.freespaces}></input>
<p>Table #: </p>
<input type="text" value={thisCard.tablenum}></input>
<p></p>
<button type="button" className="playbutton">
Save changes
</button>
</div>
)}
</>
);
}
export default Editform;
edit: apologies, I forgot to paste in the other code. Here it is. Note that I'm just hardcoding in a couple of cards for now:
import React from "react";
import ReactFitText from "react-fittext";
import Editform from "./Editform";
function Displaycards({ lastid }) {
const [cards, setCards] = React.useState([
{
id: 1,
gamename: "El Dorado",
maxplayers: 4,
freespaces: 1,
tablenum: 5,
},
{
id: 2,
gamename: "Ticket to Ride",
maxplayers: 4,
freespaces: 2,
tablenum: 3,
},
]); // using the React state for the cards array
const [showForm, setShowForm] = React.useState((false);
return (
<div className="cardwrapper">
{cards.map(({ id, gamename, maxplayers, freespaces, tablenum }) => {
return (
<div key={id}>
<div>
<div className="card">
<ReactFitText compressor={0.8}>
<div className="gamename">{gamename}</div>
</ReactFitText>
<div className="details">
<p>Setup for: </p>
<p className="bignumbers">{maxplayers}</p>
</div>
<div className="details">
<p>Spaces free:</p>
<p className="bignumbers">{freespaces}</p>
</div>
<div className="details">
<p>Table #</p>
<p className="bignumbers">{tablenum}</p>
</div>
<button type="button" className="playbutton">
I want to play
</button>
<br />
</div>
<div className="editbuttons">
<button
type="button"
className="editbutton"
onClick={() => setShowForm(!showForm)}
>
Edit
</button>
<button type="button" className="delbutton">
X
</button>
</div>
{showForm && (
<div>
<Editform
cards={cards}
setCards={setCards}
id={id}
/>
</div>
)}
</div>
</div>
);
})}
</div>
);
}
export default Displaycards;
I feel like I'm missing something obvious, but I can't get my head around what it is. The current iteration of it is here - https://github.com/TSDAdam/lfp/tree/usestate-trial - and it was created with create-react-app .
It sounds like you have one state controlling all of the Cards. You haven't shown the Card component yet however. Have every Card control its own state, so when the edit button bound to the card is clicked, it only applies to that one card. If you show us more code we can narrow it down, but this is most likely the gist of your problem.
The problem is that the EditForm is inside the map function, so for every item in your cards array, a separate EditForm is rendered with the corresponding values, and all these EditForms get shown/hidden based on the same boolean in your state.
The solution is to move the EditForm outside the map function, and create a new state object that tracks an "active" card, from where the single EditForm could take its values.
This of course won't work if you want to render the EditForm in a position relative to the "active" card.
[Edit]
Okay, I ended my answer with a caveat, but I should add a solution for that as well, since it isn't very complicated.
If you want to render an EditForm below the selected card, for example, the approach would be to keep it inside the map function as it is now, and change the boolean state variable showForm into one that accepts a string/number (depending on what you use as the identifier for each card). And then use this state variable to determine which form shows at any given time.
const [showForm, setShowForm] = React.useState("");
{cards.map(({ id, gamename, maxplayers, freespaces, tablenum }) => {
return (
<div key={id}>
// Rest of the JSX
<div className="editbuttons">
<button
type="button"
className="editbutton"
onClick={() => setShowForm(id)}
>
Edit
</button>
<button type="button" className="delbutton">
X
</button>
</div>
{showForm == id && (
<div>
<Editform
cards={cards}
setCards={setCards}
id={id}
/>
</div>
)}
</div>
</div>
);
})}
I have two separate button like grid and list button:
<button
onClick={() => setClassName('jsGridView')}
title="Grid View"
>
<IoGrid className="active" size="25"/>
</button>
<button
onClick={() => setClassName('jsListView')}
title="List View"
>
<BiAlignLeft size="25"/>
</button>
const [cName, setClassName] = useState('jsGridView');
So when i click Grid view button it will show this component:
<GridCard className={cName}/>
and when i click list view button it will show
<ListCard className={cName}/>
with this mentioned className..
class is changed button but show hide component is not working.
You can display different components depending on the value of cName.
<div className="row mt-4 book-div">
<div className={cName}>
{ cName === 'jsGridView' ? <BooksGridCard/> : <BooksListCard/> }
</div>
</div>
I want to add button to my form to dynamically add inputs. Yet I found that, if i added a button to my form that simply logs to the console, (and when I try to add inputs) it logs and then the form breaks. The front end window of my Electron app crashes (doesn't exit but turns grey) and automatically restarts on the same page without the dialog open that contains the form.
Here is a snippet of my form code:
TaskCreation.js
return (
<div className="modal-body">
{values.products.map((product, i) => {
return(
<div key={i}>
<Form.Row>
<Form.Group as={Col} controlId={"keywords-" + i}>
<Form.Label>Keywords (e.g. '+box +logo +tee')</Form.Label>
<Form.Control
value={product.keywords.join(' ')}
onChange={handleChange}
>
</Form.Control>
</Form.Group>
</Form.Row>
...
<div style={{ marginTop:'10px' }}>
<button onClick={() => console.log(123)}>Add Product</button> // this breaks when clicked
</div>
...
);
Any help is welcome, let me know what other information I should provide.
I think that the button activates the 'submit' from form. So, you can try somethings. Add the atribute type="button" to your button, and/or use ".preventDefault()".
const handleButton = (event) => {
event.preventDefault()
console.log(123)
}
<div style={{ marginTop:'10px' }}>
<button type="button" onClick={handleButton}>Add Product</button>
</div>
I would like to implement a signature system inside my form, I use "react-signature-canvas" for this.
Unfortunately, when I try to use it some problem appears.
My main problem is the reloading my page. Usually in React When you update something ,just the render changing without reloading. But here it does ... Is it linked to the canvas system ? I don't want the reload of my page... It's so ugly for a PWA.
For example when I click on "clear" or "trim" the page reload.
This is my code: I removed some parts of it to be clearer
const Consultation4 = () => {
const sigPad = {}
const [trimmedDataUrl,setTrimmedDataUrl] = useState(null);
const clear = () => sigPad.clear();
const trim = () => {
setTrimmedDataUrl(sigPad.getTrimmedCanvas().toDataURL('image/png'));
}
...
(In the render)
<FormGroup tag="fieldset" className="form-group">
<div className="container">
<div className="row">
<div className="col-4 margin-left--12px">
<legend>Please sign here:</legend>
</div>
<div className="col-4 margin-button-clear">
<button onClick={clear} className="btn btn-outline-secondary btn-sm">Clear</button>
</div>
<div className="col-4 margin-button-clear">
<button onClick={trim} className="btn btn-outline-secondary btn-sm">Trim</button>
</div>
</div>
</div>
<div className='border_grey'>
<SignaturePad ref={sigPad} />
</div>
</FormGroup>
{trimmedDataUrl ? <img src={trimmedDataUrl}/> : null}
}
Could you help me please ? Thanks in advance
PS: I have a second little problem, when I try to use sigPad.isEmpty() the compilator said "this method does not exist". But it exist in the doc of signature-pad-canvas (https://www.npmjs.com/package/react-signature-canvas).
The default type of button elements issubmit. Try button tags like
<button type="button" ....
within the form to stop submission from them. Text input elements may also need attention to stop pressing enter from submitting the form as well.
i am new to reactjs. I want to access state of a repeated react component. My code is
{Object.keys(this.state.sharing).map((share)=>{
return(<Sharings />)
})}
above component is repeated 3 times
The Sharing Component contains radio buttons and button.
When the radio button is clicked then only button is enabled.
Here is my code
<div className="col-xs-12 col-md-4">
<div className="book-now-card p-b-10" style={{height:height}}>
<div className="single-sharing" style={{height: '180px'}}>
<h3 className="single-sharing-heading">{props.heading}</h3>
</div>
<div className="m-t-20">
{
props.rent.map((rent)=>{
return(
<div className="m-10" key={rent}>
<input type="radio" name={'radio'} className="m-l-20 " onClick={(e)=>{this.handleChange(rent,e)}} /> <span className="m-l-20" style={{color:'#009688'}}>₹ {rent}</span>
<p className="m-l-55 f-s-12" style={{color: '#65747a'}}>{props.details}</p>
</div>
)
})
}
</div>
<div className="m-20">
<button className="btn btn-secondary col-6 select-rent" disabled={true} onClick={(e)=>{this.proceed(e)}} id={'Button'+this.props.num}>SELECT</button>
</div>
</div>
</div>
I want disable button in button in 1st and 3rd sharing component when radio button in 2nd sharing Component is clicked. I tried DOM manipulation with document.getElementById but click function in button stopped working.
Your input component should be controlled component
In your map method you should have something like this:
<input
type="radio"
name={'radio'}
className="m-l-20 "
value={this.state.radiosValues[index]} {/* get radio value from state */}
onClick={()=>{ // We don't need event because we work with booleans
const radiosValues = this.state.radiosValues
radiosValues[index] = !radiosValues[index] // If true we want false, if false we want true
this.setState({ radioValues})
}}
/>