Disable button from clicking the parent element - javascript

I am building a Material UI app. I have a card component and I need to make it clickable. But there is also a button on the top right corner which edits the card on click. The problem is, when I click on that button, it'll handle 2 actions:
the edit action called on the button itself
clicks the card
Here is a snippet of code:
<CardActionArea href={`/${item.name}`}>
<Card key={index}>
<CardHeader
action={
<Fab color="secondary" onClick={handleClick}>
<EditIcon color={"primary"} />
</Fab>
}
/>
<CardContent className={classes.cardContent}>
<Avatar className={classes.avatar} alt={item.name} src={item.avatar} />
<Typography variant="h6" color="textSecondary">
Card description
</Typography>
</CardContent>
</Card>
</CardActionArea>
How could I achieve that?

In the card component you create both functions you want to run when clicking the card and the inner button:
const onCardClick = () => {
// your code here
}
const onButtonClick = () => {
onCardClick()
// your code here
}
In Card.jsx when rendering the button inside the card add the onButtonClick function
<MyButton onClick={onButtonClick}
then in your button component, you give it an onClick prop:
const MyButton = (props) => {
<Button onClick={prop.onClick}>title</Button>
}

Related

How to show/hide buttons onFocus/onBlur below the textarea and allow to click it?

I need to add two buttons below the input field.
One button will allow saving the input in the textarea, and another aborting.
The buttons should be displayed when the input is focused.
Currently, the problem is that when I click any of the buttons, the input gets blurred again and thus they disappear and the onClick event doesn't happen.
I use MUI and Formik.
Can anyone tell me how to fix it?
const [buttonClicked, setButtonClicked] = useState(false);
...
return (
...
<Box sx={inspectionWrapperStyles} mb={'0.25rem'}>
<MultiLineInput
name={fieldName}
noMargin
required={required}
label={label}
onFocus={() => setInputFocused(true)}
onBlur={() => setInputFocused(false)}
ref={inputRef}
/>
{inputFocused && (
<>
<IconButton
altText=""
onClick={() => {
console.log('Saved');
}}
>
<SaveIcon />
</IconButton>
<IconButton
altText=""
onClick={() => {
console.log('Aborted');
}}
>
<XCircleIcon />
</IconButton>
</>
)}
</Box>
...
)
Looks like currently as you click a button the focus of the input is lost, so they disappear. Maybe it's a good idea to check if the button is clicked and only then hide it, like this:
{inputFocused && !buttonClicked (
then in both button's onClick you can add:
onClick={() => {
console.log('Aborted');
setButtonClicked(true);
}}
only thing left is to make sure that we reset it when input is focused again:
onFocus={() => {
setInputFocused(true);
setButtonClicked(false);
}}
const [showButton, setShowButton] = useState(false); // add this
<MultiLineInput
name={fieldName}
noMargin
required={required}
label={label}
onFocus={() =>{
setInputFocused(true)
setShowButton(true) // add this
}}
onBlur={() => setInputFocused(false)}
ref={inputRef}
/>
{inputFocused && showButton && (
<>
<IconButton
altText=""
onClick={() => {
console.log('Saved');
setShowButton(false) // add this if you want to hide buttons
}}
>
<SaveIcon />
</IconButton>
<IconButton
altText=""
onClick={() => {
console.log('Aborted');
setShowButton(false) // add this if you want to hide buttons
}}
>
<XCircleIcon />
</IconButton>
</>
)}

Prevent child component from triggering parent's onClick

Using Material-ui in React, I want to have the <IconButton> to have one behavior with onClick (quickly add to the cart) and have the parent <GridListTile> to have a different onClick behavior (open the more info Dialog for that item).
My issue is that when I click on the <IconButton>, it does both actions at the same time (open the more info Dialog AND add to the cart.
Is there a way to have <IconButton> to not inherit the onClick from the parent component?
<GridListTile key={tile.title}>
<img
src={`/${tile.img}`}
alt={tile.title}
onClick={handleClickOpen()}
/>
<GridListTileBar
title={tile.title}
subtitle={<span>{tile.description}</span>}
onClick={handleClickOpen()}
actionIcon={
<Tooltip title="add to cart">
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
// onClick={handleClickOpen()}
onClick={() => {
dispatch({ type: "cart-increment" });
}}
>
<AddShoppingCartIcon />
</IconButton>
</Tooltip>
}
/>
</GridListTile>
In the child handler, stop the event from propagating upward:
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
onClick={(e) => {
e.stopPropagation();
dispatch({ type: "cart-increment" });
}}

click the text box text a popup menu should open with text box

when I click the text box text a popup menu should open with text box.
similarly when I click a filter icon in the right side corner a menu should open with list of checkboxes.
but right now whats happening is both the menus are opening when I click at both the places.
only one menu should open from one location.
I debugged by putting consoles. the problem is with the below methods
`const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClickFilter = event => {
setAnchorEl(event.currentTarget);
};`
can you tell me how to fix it.
providing my code snippet and sandbox below.
https://codesandbox.io/s/material-demo-kpt5i
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClickFilter = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleCloseFilter = () => {
setAnchorEl(null);
};
<Typography variant="h6" id="tableTitle" onClick={handleClickFilter}>
text box
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseFilter}
>
<MenuItem onClick={handleCloseFilter}>
<form
className={classes.container}
noValidate
autoComplete="off"
>
<TextField
id="standard-name"
label="Name"
className={classes.textField}
// value={values.name}
// onChange={handleChange('name')}
margin="normal"
/>
</form>
</MenuItem>
</Menu>
</Typography>
<Tooltip title="Filter list">
<IconButton aria-label="filter list">
<FilterListIcon onClick={handleClick} />
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
value="name"
/>
Dessert
</MenuItem>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
value="calories"
/>
Calories
</MenuItem>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
/>
Fat
</MenuItem>
Alright, you had a couple issues on your code that was preventing this from working properly.
The idea of the 'anchor' element it's that the menu will attach to that DOM object and render right next to it; this is all handled for you by Material and it works like a charm but the thing it's that you need to have this anchors properly set.
First, you need a way to differenciate an anchor element for each menu you want to display (which in your case, it's two).
For this case to work, I used a 'type' prop inside of your anchor state object and another prop called 'target' which is the one that will store the 'event.currentTarget'. Something like this: { type: 'icon', target: event.currentTarget }
Then, you need to have each anchor element (which can be a button, an icon, a label, H1 or whatever you want) separated from the Menu component itself; if you do otherwise, then the Menu will never disappear and it can only be closed using TAB or refreshing. Something like this:
<Typography variant="h6" id="tableTitle">
<span onClick={handleClickFilter}>NOTICE THIS LABEL HAS THE MENU TRIGGER FUNCTION</span>
<Menu
id="simple-menu"
anchorEl={anchorEl && anchorEl.type === 'textbox' && anchorEl.target}
open={Boolean(anchorEl && anchorEl.type === 'textbox')}
onClose={handleClose}
>
<MenuItem>
<form
autoComplete="off"
>
<TextField
label="Name"
margin="normal"
/>
</form>
</MenuItem>
</Menu>
</Typography>
Then, finally you need the anchor handler functions, which at this point it's handled by a hook and it's storing with the same variable name except it's modifying the 'type' prop I mentioned before.
const handleClick = event => {
setAnchorEl({ type: 'textbox', target: event.currentTarget })
}
const handleClose = () => {
setAnchorEl(null)
}
This should do the work successfully.
Anyway, I modified your codepen code and updated it right here.
Hope this helps!

How to pass (this) props to sibling components in React

I'm mapping a list of data in which each listing has a button which opens a modal to display a full listing's data. Except instead of mapping each entry with a button containing its own modal component mapped per each listing, I'd like to have each button trigger an outside modal component.
handleTaskModal = () =>{
<TaskModal {...state} />
}
render() {
const { tasks } = this.state;
return (
<div>
<Container color="light">
<Row className="flex-row">
{tasks.map(({ name, image, description }) => (
<Col key={name}
xs="11"
sm="6"
lg="4"
className="mx-auto my-sm-2 my-lg-1"
>
<Card className="task-card border-0 rounded shadow-sm my-3">
<CardImg
top
width="100%"
src={image}
style={{
width: "100%",
height: "45vh",
objectFit: "cover"
}}/>
<CardBody>
<CardTitle className="card-title p-0 text-left">{name}</CardTitle>
</CardBody>
<Button
color="primary"
className="w-50 rounded mb-3 mx-auto shadow-sm"
style={{
borderRadius:"20px"
}}
onClick={this.handleTaskModal}
> View Task
</Button>
</Card>
</Col>
))}
</Row>
</Container>
</div>
);
}
I want to share props between each entry to one modal component
You don't do this in react. Data always flows from parents to children, never between siblings. Actions can flow up from a child to the parent by providing a handler. The correct way to solve this is to store the currently viewed task in the parent state and display the modal accordingly:
class Tasks extends Component {
state = {
viewed: null,
};
handleShow = name => this.setState({viewed: name});
handleClose = () => this.setState({viewed: null});
render() {
const {tasks, viewed} = this.state;
return (
<div>
<Container>
<Row>
{/* details omitted for simplicity */}
{tasks.map(({name, image, description}) => (
<Col key={name}>
<Button onClick={() => this.handleShow(name)}>View Task</Button>
</Col>
))}
</Row>
</Container>
{viewed && (
<TaskModal
task={tasks.find(task => task.name === viewed)}
onClose={this.handleClose}
/>
)}
</div>
);
}
}
Also note that handlers should modify the state to trigger a re-render. Returning something from them (e.g. components) doesn't have any effect.

Reactstrap modals all open on button click

I'm having trouble with the reactstrap modals. I'm looping through an array and it makes modals and buttons, and gets information in a nice card.
Now when I click on a button to open the modal, all modals open even if I didn't click the button on the card. All (39) open. I was hoping you all could help me out <3
Modal State
this.state= {
modal:false,
}
Toggle Function
toggle(){
this.setState(prevState =>({
modal: !prevState.modal
}));
}
Everything that gets returned
return (
<div key={item.ID}>
<ul>
<Modal isOpen={this.state.modal} toggle={this.modal} id={item.ID}>
<ModalHeader id={item.ID} toggle={this.toggle}>{item.Naam}</ModalHeader>
<ModalBody>fdass</ModalBody>
<ModalFooter><Button onClick={this.toggle} color='primary'>fddss</Button></ModalFooter>
</Modal>
<Card style={{ width: '18rem' }}>
{/* <CardImg src={"http://static.floraxchange.nl/artikelen/"+ item.Fotos.ID +"_v_t8.jpg"} alt={item.Naam} /> */}
<Card.Body>
<Card.Title>{item.Naam}</Card.Title>
<Card.Text>
Hoogte: {item.Hoogte}<br />
Potmaat: {item.Potmaat} <br/>
ID: {item.ID}
</Card.Text>
<Button color="danger" data-target={'#' + item.ID} onClick={this.toggle}>More information</Button>
</Card.Body>
</Card>
</ul>
</div>
)

Categories

Resources