Passing props of click event inside new component - reactjs

When I use standard button with onClick props event it works perfectly fine
<Button onClick={handleClose}>
Agree
</Button>
But I have also created my new component called ButtonSave and onClick is not working
<ButtonSave text="Agree" onClick={handleClose} />
My code inside ButtonSave component
export default function IconLabelButtons(props) {
const classes = useStyles();
return (
<div>
<Button
variant="contained"
color="primary"
size={props.size}
className={classes.button}
startIcon={<SaveIcon />}
>
{props.text}
</Button>
</div>
);
}
How am I supposed to use my handleClose right there?

You need to update your ButtonSave component and pass the onClick prop to it like:
export default function IconLabelButtons(props) {
const classes = useStyles();
return (
<div>
<Button
variant="contained"
color="primary"
size={props.size}
className={classes.button}
startIcon={<SaveIcon />}
onClick={props.onClick}
>
{props.text}
</Button>
</div>
);
}
Hope it works for you.

You need to use onClick which provided in props:
// <ButtonSave text="Agree" onClick={handleClose} />
const ButtonSave = ({ onClick, text }) => (
<Button onClick={onClick}>{text}</Button>
)

Based on the code you provided, it may be because you didn't pass it from ButtonSave to its child of Button. So:
export default function(props) {
return (
<Button onClick={props.handleClose} />
);
}

Related

React render not changing when calling from Button

When I click the login or register button in the following react code, the renderView() function is not rendering the Login(or the Register) component on the page.
When I log the value of e.currentTarget.value in the console, the correct values are getting logged when the button is clicked.
How do I fix this?
I want the corresponding components to be displayed when I click the Login or Register Buttons
const AppHomePage = () => {
const classes = useStyles();
const [renderVal, setRenderVal] = useState(0);
const renderView = () => {
switch(renderVal){
case 0:
return <Page />
case 1:
return <Register />
case 2:
return <Login />
default:
return <Page />
}
}
const ButtonChange = (e) => {
setRenderVal(e.currentTarget.value);
}
return(
<div>
<AppBar className={classes.root} position='static' >
<Toolbar className={classes.appbar}>
<Button className={classes.buttons} value={1} variant="contained" color="primary" onClick={ButtonChange}>
Register
</Button>
<Button className={classes.buttons} value={2} variant="contained" color="primary" onClick={ButtonChange}>
Login
</Button>
</Toolbar>
</AppBar>
<div>
{ renderView() }
</div>
<CssBaseline />
</div>
)
}
const Login = () => {
return(
<div>
<p>login</p>
</div>
)
}
const Register = () => {
return(
<div>
register
</div>
)
}
const Page = () => {
return(
<div>
page
</div>
)
}
Pass the value inside onClick function. Use an arrow function and pass the id like 1 or 2. onClick={() => ButtonChange(1)}
<Button className={classes.buttons} variant="contained" color="primary" onClick={() => ButtonChange(1)}>
Register
</Button>
<Button className={classes.buttons} variant="contained" color="primary" onClick={()=>ButtonChange(2)}>
Login
</Button>
Now in ButtonChange function get the value passed in previous step.
const ButtonChange = (id) => {
setRenderVal(id);
}
I fixed it by simply changing the cases from case 1: to case '1': and so on...

React - how to invoke popup window in my case?

I'm not a React expert yet thus I have a question for you - how to invoke my popup window from:
import {options, columns,convertToArray} from './consts'
const index = () => {
const {data, loading, error, performFetch} = fetchHook({path: "/xxx/yyy", fetchOnMount: true})
return (
<div className={classes.Container}>
<h1>List of products</h1>
<Divider className={classes.Divider} />
<ProductTable data={convertToArray(data)} options={options} columns={columns}/>
</div>
)
}
export default index;
consts.js
export const actions = (productPropertyId, showModal) => {
const productDetails = (productPropertyId) => {
}
const removeProduct = (productPropertyId, showModal) => {
actions(productPropertyId, showModal);
return (
<div className={classes.actionsContainer}>
<Button
onClick={() => productDetails(productPropertyId)}
> {"More"}
</Button>
<Button
const removeProduct = (productPropertyId, showModal) => {
actions(productPropertyId, showModal);
>{"Remove"}
</Button>
</div>
)
};
export const convertToArray = (productList) => {
let products = []
if (productList != null) {
productList.map(product => {
column1, column2, column3, actions(product.id)]
products.push(prod)
})
}
return products;
};
My popup is --> <FormDialog/> based on react Materials.
Is it possible to invoke popup in this place?
I have a react material table with some columns. The last column contains 2 buttons, one of them is "Remove" (row). Here I want to invoke my popup. Maybe I should rebuild my structure?
UPDATE
Below is my popup - I wonder how to run this popup from the place above:
const formDialog = (popupOpen) => {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
{/*<Button variant="outlined" color="primary" onClick={handleClickOpen}>*/}
{/* Open alert dialog*/}
{/*</Button>*/}
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Subscribe</DialogTitle>
<DialogContent>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates
occasionally.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Email Address"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Subscribe
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default formDialog;
UPDATE 2
I updated my code taking into cosideration the tips from your response, see above. Can I add a parameter showModal in my export const actions = (productPropertyId, showModal) and then invoke this component with different showModal value? UNfortunately my popup doesn't appear when I click on Remove button :(
You can invoke it conditionally and controle it using some state variable. Like this:
const [removeModal, removeToggle] = useState(false);
return (<>
<div className={classes.actionsContainer}>
<Button
onClick={() => productDetails(productPropertyId)}
> {"More"}
</Button>
<Button
onClick={() => removeToggle(true)}
>{"Remove"}
</Button>
</div>
{removeModal ? <YourComponent /> : ''}
</>
)
I'm using a react fragment there <></> just to position the modal div outside the main div, but you can also invoke it inside your main div as well (I usually do this and set the position: fixed so the modal/popup coud appear in top of everything).

onClick Rendering is not happening ReactJs

I am creating a web application with react.js also using react-bootstrap.
What I want to accomplish is when user click on button then modal will appear but that is not happening.
Button code
<div className="rightButtons">
<button name="updateItem" className="btn btn-primary" onClick={() => { this.onUpdateItem(this.props.selectedAppTypeId)}} >Update Item</button>
</div>
function which will be called.
onUpdateItem = (id) => {
return (
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}
Any help would be great help. Thanks.
You are returning HTML into your onClick handler, and not into the Component's render method. If you want to show HTML content after an onClick, you need to actually return those HTML elements within the actual render. Try this:
class Component extends React.Component {
state = {
showModal: false
}
renderModal = () => {
return (
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}
render() {
return(
<div>
<button onClick={() => this.setState({showModal:true})}> Show </button>
{this.state.showModal && this.renderModal()}
</div>
)
}
}
Edit: You can also export that entire Modal return statement into its own component, and conditionally render the component when the showModal state is true.
const ModalComponent = (props) => {
return(
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
)
}
class ParentComponent extends React.Component {
state = {
showModal: false
}
render(){
return(
<div>
<button onClick={() => this.setState({showModal:true})}>
Show Modal
</button>
{this.state.showModal && <ModalComponent id='0af141random'/>}
</div>
)
}
}
The problem that you have is that you're passing a react function component as an event handler; the return value of the function is a react component, but calling the function by itself won't mount that component in the DOM and display it.
A better way to make this happen might be to place your Modal component in your component hiearchy, and control whether it is shown by using a callback to change the state of a parent component.
Something like this:
class ParentComponent extends React.Component {
showModal() {
this.setState{
modalActive: true;
}
}
render() {
<div>
<Button onClick={showModal}>Show me the modal!</Button>
<Modal active={this.state.modalActive} />
</div>
}
}
const modalComponent = (props) => {
return (<div style={{ display: (props.isActive) ? "block" : "none "}}>
<h1>I'm a modal!</h1>
</div>)
}
I haven't checked, but I'm sure React Bootstrap has its own prop for displaying/hiding modals.
EDIT: Here's a code example from the react bootstrap documentation that shows it in use https://react-bootstrap.github.io/components/modal/#modals-live

React Passing data to components

I have a parent stateful component and i pass the state of show dialog to a stateless header component.
When a icon clicked on the header component it opens a stateless dialog component.
In the stateless dialog component i want to be able to enter data into a text-field.
Do i have to completely change my code to make the stateless dialog to a stateful component?
Below is my code. If anyone can recommend the best way of doing this. Thanks.
class Layout extends Component {
state = {
show:false
}
toggleSidenav = (action) =>{
this.setState({
showDialog:action
})
}
render(){
return(
<div>
<Header
showNav={this.state.showDialog}
onHideNav={() => this.toggleSidenav(false)}
onOpenNav={() => this.toggleSidenav(true)}
/>
</div>
)
}
}
export default Layout;
Header component
const Header = (props) => {
console.log(props.onOpenNav)
const navBars = () => (
<div>
<AppBar position="static">
<Toolbar>
<IconButton color="inherit" aria-label="createfolder">
<SvgIcon>
<path d={createfolder}
onClick={props.onOpenNav}
name="firstName" />
</SvgIcon>
</IconButton>
</Toolbar>
</AppBar>
</div>
)
return (
<div>
<SideNav {...props} />
<div>
{navBars()}
</div>
</div>
)
}
Dialog Component
const DialogBox = (props) => {
return (
<div>
<Dialog
open={props.showNav}
aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Add Folder</DialogTitle>
<DialogContent>
<TextField
margin="normal"
/>
</DialogContent>
<DialogActions>
<Button onClick={props.onHideNav} color="primary">
Cancel
</Button>
<Button onClick={props.onHideNav} color="primary"
onChange={this.handleFieldChange}
value={this.value}
>
Create
</Button>
</DialogActions>
</Dialog>
</div>
)
}
Since component Header is readily stateful. You could initialize its state to
state = {
show:false,
formData: {} //later, you may save user input from the child component here
}
and in Header component, you may add a function:
handleInputEntered = (event) => {
const _data = { ...this.state.formData };
_data[event.target.name] = event.target.value;
this.setState({
formData: _data
});
}
and make sure to pass this new function as a prop to like this:
<Header
handleInputEntered = {this.handleInputEntered}
/>
and set onChange to be this new function where you have input field:
<TextField
onChange={this.props.handleInputEntered}
/>
It seems you're using MaterialUI, so just look up how you may supply the onChange property to TextField component.
Is this clear?

Stop button nested inside a form from submitting and have it fire a different function

I have a close button nested inside a form that is supposed to reset the form and close the popup modal the form is sitting on.
I've changed the button type from the default submit to type='reset' and have an onClick that is supposed to fire my resetting/closing function, but the function is never being called and instead the submit function is called.
is that not possible with jsx or what am I missing?
(Note that Button is just a component wrapping a <button> html tag)
import Button from '../../../components/Button'
export const SomeForm = (props) => (
<form className='quote-form__wrapper' onSubmit={props.onSubmit}>
<Button
className='close-btn'
type='reset'
onClick={props.resetForm}
value='CLOSE' text='x' />
some form fields...
<Button
className='btn ripple-btn'
type='submit'
text={props.btnText} />
</form>
)
EDIT:
I should add that when I don't use a custom Button component to render the button element it does work even though I don't change the button type the right function (resetForm) is being called:
const someForm = (props) => (
<form onSubmit={props.onSubmit}>
<div>
<button className='close-btn' onClick={props.resetForm} value='CLOSE'>
x
</button>
some form fields...
<button
className='ripple-btn btn'
type='submit'>
{props.btnText}
</button>
</div>
</form>
)
For what it's worth the Button component looks like this:
const Button = (props) => (
<button className={props.className} {...props.attributes}>
{props.text}
</button>
)
export default Button
You aren't passing down the other props properly in your Button component. You should use {...props} and not {...props.attributes}.
const Button = (props) => (
<button className={props.className} {...props}>
{props.text}
</button>
);
export default Button;
Any props that you don't want to pass directly to the button could be obtained from the props using object destructuring:
const Button = ({text, className, ...props}) => (
<button className={className} {...props}>
{text}
</button>
);

Resources