I have several cards mapped from an API. Each card has a button, that when clicked, expands the grades section for each card. My issue is that, ALL buttons only trigger the first card.
function showGrades() {
let showAllGrades = document.getElementById('allGrades')
if (showAllGrades.style.display === '' || showAllGrades.style.display === 'none') {
showAllGrades.style.display = 'inline-block'
} else {
showAllGrades.style.display = 'none'
}
}
return (
<>
<Card className={"d-flex flex-row flex-wrap border-0"}>
<Card.Img className='m-2' src={student.pic} style={{width:'8em', height:'8em', border:'1px solid black', borderRadius:'100px'}} />
<Card.Body>
<Card.Title as='h1'><strong>{student.firstName + ` ` + student.lastName}</strong></Card.Title>
<span style={{float:'right'}}>
<Button onClick={(e) => showGrades(e.target.id)} type='button' style={{background:'none', border:'none'}}>
<i className='fa fa-plus' style={{fontSize:'24px', color:'#b2b2b2'}}></i>
</Button>
</span>
<Card.Text className="ps-4" as='p'>Email: {student.email}</Card.Text>
<Card.Text className="ps-4" as='p'>Company: {student.company}</Card.Text>
<Card.Text className="ps-4" as='p'>Skill: {student.skill}</Card.Text>
<Card.Text className="ps-4" as='p'>Average: {student.grades.reduce((a, b) => a + parseFloat(b), 0) / student.grades.length}</Card.Text>
<div id='allGrades' style={{paddingLeft:'1.5rem', display:'none'}}>
{student.grades.map((grade, index) => {
return (
<>
<div className='d-flex flex-column justify-content-center'>Test {index + 1} {grade}</div>
</>
)
})}
</div>
<span style={{paddingLeft:'1.5rem'}}>
<Button type='button' className='bg-light' style={{color:'#000'}}>new tag</Button>
</span>
</Card.Body>
</Card>
</>
)
}
Sandbox to see what's actually going on: https://codesandbox.io/s/optimistic-keldysh-9cqgxy?file=/src/App.js
Thanks
Firstly, to immediately fix your problem, you'll need to use a unique id for each card. By creating a unique identifier suffix, you can avoid errors with getElementById('allGrades').
function showGrades(indexFromParentMapping) {
let showAllGrades = document.getElementById(
`allGrades-${indexFromParentMapping}`
);
...
}
In general, it is bad practice to use getElementById within a react app, as you can already access a specific element without needing to grab an id, since you have an event associated with your button click on each independent card. consider using react to your advantage and passing a value into the function that you can use to smartly access a more complex state object stored a level up in the parent, instead of on the child.
Your card render will eventually look like this, with the function and state to open and view graded above lifted to the parent:
...<div id={`allGrades-${props.index}`} ... />...
read more here: https://reactjs.org/docs/lifting-state-up.html