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 card mapped with data from an "json" file and want the same details on the card to display on the modal menu
In the code snippet is the code for the cards that are displayed and the modal the modal works properly (opens and closes) but I now want to use the data from the cards in the modal but it doesn't show. I used the card key to specify which cards data to use but don't think that it works this way. I am new to react and think I need to use props but can't find any material that can explain it in a way I understand. Please help if you can any critsism will be gladly accepted and any other ways to improve my code will also help. Any learning material will also be hugely helpful.
Code:
{
details.map((details) => {
return (
<div className="card" key={details.id}>
<img src={details.image} alt="" />
<h5 className="board-name">{details.design}</h5>
<p className="board-size">Size: {details.size}</p>
<h6 className="board-price">{details.price}</h6>
<button className="add-to-cart" onClick={() =>
setModalDisplay(true)}> click me
</button>
</div>
)
})
}
{modalDisplay &&
<div className="backdrop">
<div className="cart-card" key={details.id}>
<div className="item-details">
<img src={details.image} alt="" width="98px" height="98px" />
<h4 className="item-name">{details.design}</h4>
<p className="item-size">{details.size}</p>
<h6 className="item-price">{details.price}</h6>
<button className="exit-modal" onClick={() =>
setModalDisplay(false)}>
</button>
</div>
<span className="modal-inputs">
<button className="minus-btn">-</button>
<input type="text" className="amount-input" value="01" />
<button className="plus-btn">+</button>
<button className="add-btn">Add to cart</button>
</span>
</div>
</div>
}
</div>
You could store the card data in an onClick that sets it in an state for example and use the state in the modal as props or directly. I think that would be the best option to use in this case.
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'm having a problem where clicking anywhere inside a separate div is causing the radio button to change to the first radio button. I don't know why this is happening as the panel div for adding payments is completely separated from the radio label.
Basically, I have a bunch of cards in a list, clicking the radio button selects the cards. When I try to fill out the fields to add a payment method, clicking anything within the box causes the radio button to go back to the first card. How is the handleRadioChange method propagating to the panel div?
<div id="payment_methods" style={{margin: '10px'}}>
<div className="group">
{methods.map((method, key) => {
return (
<label>
<span>
<input type="radio"
name={method.id}
value="saved-card-1"
style={{verticalAlign: 'middle', margin: '0px'}}
checked={radio == method.id}
onChange={handleRadioChange}
/>
</span>
</label>
)
})}
<label>
<span>
<input type="radio"
name="add-card"
value="add-card"
style={{verticalAlign: 'middle', margin: '0px'}}
checked={radio == 'add-card'}
onChange={handleRadioChange}
/>
</span>
<div className="box-root hideIfEmpty">
<div className="box-root">
<div className="box-root flex flex-row flex-justify-flexstart flex-wrap">
<div className="flex flex-align-baseline flex-row">
<div className="flex align-baseline flex-row flex-justify-flexstart">
<span className="button-link-label text-proportional text-typeface text-wrap-nowrap text-gray">
<span> Add Payment Method </span>
</span>
</div>
</div>
</div>
</div>
</div>
</label>
</div>
</div>
<CSSTransition
classNames="method"
in={radio === 'add-card'}
timeout={100}
unmountOnExit>
<div className="panel panel-primary">
</CSSTransition>
This is my handleRadioChange method
const handleRadioChange = async (e) => {
console.log(e.target);
setRadio(e.target.name)
if (e.target.name == 'add-card') {
console.log('Creating payment fields')
}
}
The event on your input is propagating to the label, which contains everything else inside your card. Try adding e.preventDefault() to your handler, or moving non-input elements outside of your label element. You're also using a unique name attribute for each payment method in your array. That would prevent them from acting as a single radio group.
I am creating a clone of the Netflix web app. I am currently developing the landing page. I have included my code below. This is one of the few different ways I have attempted structuring this page.
The layout currently is appearing how I want it to look, however the "main-slice__language-button" and the "main-slice__signin-button" at the top of the page are not working – meaning nothing happens when I click the select dropdown, and the Sign In button is not appearing as clickable. Can anyone explain why it does not work this way and any suggestions for better alternatives?
screenshot of landing page
import backgroundImage from '../../images/mooshflix-background.jpeg';
import netflixLogo from '../../images/netflix-logo.png';
import './MainSlice.css';
const MainSlice = () => {
return (
<div className='main-slice-container'>
<img className='background-image' src={backgroundImage} alt='mooshflix background' />
<div className='header'>
<img className='main-slice__logo' src={netflixLogo} alt='' />
<div className='main-slice__header-buttons'>
<select className='main-slice__language-button'>
<option>English</option>
<option>Spanish</option>
</select>
<button className='main-slice__signin-button'>Sign In</button>
</div>
</div>
<div className='main-slice__text-container'>
<h1 className='main-slice__title'>Unlimited movies, TV shows, and more.</h1>
<h2 className='main-slice__subtitle'>Watch anywhere. Cancel anytime.</h2>
<div className='main-slice__email-form-container'>
<h3 className='email-form-title'>Ready to watch? Enter your email to create or restart your membership.</h3>
<form>
<input placeholder='Email Address' ></input>
<button className='main-slice__email-form-button'>Get Started ></button>
</form>
</div>
</div>
</div>
)
}
export default MainSlice;```
because you DID NOT do anything, what event did u call for that button? you have to add some event listeners like onClick to your btn, like below:
const onStart = () => {
DO STH WHAT YOU WANT
}
<button className='main-slice__email-form-button' onClick={onStart}>
Get Started
</button>