I'm creating a vertical timeline with cards alternating sides as you move along the timeline, I'm trying to include a Popover effect to show more info about a person/event that fills the opposite whitespace on the timeline.
I'm trying to achieve this by using a ternary operator (using modulus to alternate sides in order) in my map callback, but it's rendering/returning both possible Popover results, onClick leads to a Popover popping on both sides of the card.
render() {
const cards = timelineObjects.map((card, i) => (
<React.Fragment key={i}>
{i % 2 === 0 ? (
<VerticalTimelineElement
className="vertical-timeline-element--work"
key={i}
iconStyle={{
background: "rgb(40,49,72)",
color: "#000"
}}
paddingTop="0em"
//icon={<Print/>}
>
<div>
<Card className="card">
<CardActionArea>
<CardMedia
style={{ height: 0, paddingTop: "100%" }}
image={card.image}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{card.title}
</Typography>
<Typography component="p">{card.subtitle}</Typography>
</CardContent>
</CardActionArea>
<Button
size="small"
color="primary"
component={Link}
//to={card.path}
onClick={this.handlePop}
>
Learn More, index: {i}, RIGHT
</Button>
<Popover
open={this.state.popped}
anchorEl={this.state.anchorEl}
anchorOrigin={{
horizontal: "right",
vertical: "center "
}}
transformOrigin={{
horizontal: "right",
vertical: "bottom"
}}
onClose={this.handleRequestClose}
>
Right popover text
</Popover>
</Card>
</div>
</VerticalTimelineElement>
)
:
(
<VerticalTimelineElement
className="vertical-timeline-element--work"
key={i}
iconStyle={{
background: "rgb(40,49,72)",
color: "#000"
}}
paddingTop="0em"
//icon={<Print/>}
>
<div>
<Card className="card">
<CardActionArea>
<CardMedia
style={{ height: 0, paddingTop: "100%" }}
image={card.image}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{card.title}
</Typography>
<Typography component="p">{card.subtitle}</Typography>
</CardContent>
</CardActionArea>
<Button
size="small"
color="primary"
component={Link}
//to={card.path}
onClick={this.handlePop}
>
Learn More, index : {i}, LEFT
</Button>
<Popover
open={this.state.popped}
anchorEl={this.state.anchorEl}
anchorOrigin={{
horizontal: "left",
vertical: "center "
}}
transformOrigin={{
horizontal: "left",
vertical: "bottom"
}}
onClose={this.handleRequestClose}
>
Left popover text
</Popover>
</Card>
</div>
</VerticalTimelineElement>
)}
</React.Fragment>
));
Your popovers are all anchored to the same element (this.state.anchorEl
) and are all configured to open based upon the same boolean (this.state.popped
). This means if you have 2+ objects in your timeline, you render a popover for each object, and all popovers will be opened or closed together and all will be to the left/right of the only anchor element (whatever that is).
You should probably create a new TimelineObject
component that renders a single timeline object and can have its own local state and assigns its own local anchorEl
to anchor its popover to. Possibly its own popped
state as well. Then your map function would be more like:
timelineObjects.map((card, i) => <TimelineObject key={i} card={card} onLeft={i%2==0} />)
Alternatively, instead of using this.state.popped
as a boolean, use it as the card index to show the popup for. And in your Popover
code do:
<Popover open={this.state.popped === i} ...
And when you set popped
set it like this.setState({popped: indexOfCardToShowPopover, anchorEl: elementOfCardToAnchorPopover });
That way only 1 popover is ever open at a time.