material-ui menu not close when dialog open - reactjs

i am using react + material-ui .
i created dialog component in jsx file like this:
export default class CartoviewAbout extends React.Component {
constructor(props) {
super(props);
this.state = {open: false};
}
_handleOpen() {
this.setState({open: true});
};
_handleClose() {
this.setState({open: false});
};
render() {
const actions = [
<FlatButton
label="Close"
primary={true}
keyboardFocused={true}
onTouchTap={this._handleClose.bind(this)}
/>,
];
return (
<div>
<MenuItem
onTouchTap={this._handleOpen.bind(this)}
primaryText="Show About Dialog"
/>
<Dialog
title={title}
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={this._handleClose.bind(this)}
autoScrollBodyContent={true}
contentClassName="dialog"
bodyClassName="dialog_body"
>
<div ><p>{abstract}</p>
</div>
</Dialog>
</div>
);
}
}
and i use this component in menu in another file but then i click the menu item dialog open and menu not close:
export default class CartoviewAppBar extends React.Component {
constructor(props) {
super(props);
}
render() {
const about = appConfig.showAbout ? React.createElement(CartoviewAbout) : "";
const icon_menu = <IconMenu
iconButtonElement={<IconButton><MoreVertIcon /></IconButton>}
anchorOrigin={{horizontal: 'right', vertical: 'top'}}
targetOrigin={{horizontal: 'right', vertical: 'top'}}
>
{about}
</IconMenu>;
return (
<div>
<AppBar
title={''}
showMenuIconButton={false}
iconElementRight={icon_menu}
/>
</div>
);
}
image:
i want menu to close when dialog open

You'll need to add the Dialog component outside the IconMenu. The IconMenu's onRequestChange event wont fire until the dialog closes.

Try this may be a workaround.
_handleOpen() {
window.setTimeout(() => {
this.setState({open: true});
}, 100); //any arbitary timeout
};
MenuItem onClick will automatically trigger for closing IconMenu
I think opening Dialog suppressing the event for closing IconMenu. So opening Dialog after closing IconMenu using setTimeout

Related

Show/ Hide a div according to toggle Switch on/off

I want to display/hide the chat body when on/off the switch. That means when switch on I want to display the chat body and when to switch off I want to hide it. Below is an image of toggle switch that I have used. Can you give me help to do that?
class MyApp extends Component {
render() {
return (
<FormControlLabel
control=
{
<Switch
name="sector"
color="primary"
style={{paddingRight: "30px"}}
onClick={this.handleClick.bind(this)}
/>
}
label="Sector 1"
/>
<div className="chatBody">
This is my chat body
</div>
);
}
}
export default MyApp;
You can show/hide the div content using the React state handlers, your code then could look like this:
class MyApp extends Component {
constructor(props) {
super(props);
this.state = {showBody: false};
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
// toggle the showBody state to hide and show the body
this.setState({ showBody: !this.state.showBody })
}
render() {
return (
<FormControlLabel
control=
{
<Switch
name="sector"
color="primary"
style={{paddingRight: "30px"}}
onClick={this.handleClick}
/>
}
label="Sector 1"
/>
{this.state.showBody && (
<div className="chatBody">
This is my chat body
</div>
)}
);
}
}
export default MyApp;
As you can see on the this.state.showBody && we are declaring that the body should only display if the showBody state is true.
Then in some scenarios for "controlled inputs" there is probably a property in your Switch for the "checked" state (it usually depends on the library) and then you can use the state in the Switch to a controlled value: checked={this.state.showBody}.
Just add a state to control this:
class MyApp extends Component {
constructor(props) {
super(props);
this.state = {
checked1: false,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
this.setState({
checked1: e.target.checked,
});
}
render() {
return (
<>
<FormControlLabel
control={
<Switch
checked={this.state.checked1}
name="sector"
color="primary"
style={{ paddingRight: "30px" }}
onClick={this.handleClick.bind(this)}
/>
}
label="Sector 1"
/>
{this.state.checked1 && <div className="chatBody">This is my chat body</div>}
</>
);
}
}
export default MyApp;

React SlidingPane header getting hidden under Nav bar

This is my App.js:
export class App extends React.Component {
render() {
return (
<BrowserRouter>
<NavigationBar />
<Routes />
</BrowserRouter>
);
}
}
And this is where I am using a SlidingPane on a button click:
Product.js:
class App extends Component {
constructor(props) {
super(props);
this.state = {
isPaneOpen: false,
isPaneOpenLeft: false
};
}
render() {
return <div>
<button onClick={() => this.setState({ isPaneOpen: true })}>Click me to open right pane!</button>
<div style={{ marginTop: '32px' }}>
<button onClick={ () => this.setState({ isPaneOpenLeft: true }) }>
Click me to open left pane with 20% width!
</button>
</div>
<SlidingPane
className='some-custom-class'
overlayClassName='some-custom-overlay-class'
isOpen={ this.state.isPaneOpen }
title='Hey, it is optional pane title. I can be React component too.'
subtitle='Optional subtitle.'
onRequestClose={ () => {
// triggered on "<" on left top click or on outside click
this.setState({ isPaneOpen: false });
} }>
<div>And I am pane content. BTW, what rocks?</div>
<br />
<img src='img.png' />
</SlidingPane>
</div>;
}
}
render(<App />, document.getElementById('app'));
Apparently, the Slidingpane header is getting hidden under the NavBar. When I remove the navbar, I can see the SlidingPane header, but when I add it, it is getting display beneath it. How do I make my Pane to be independent of the NavBar?
You can increase CSS z-index of Slidingpane. If needed you should set position: "relative" If you are writing inline styles you can set it like
style={{zIndex: "10", position: "relative"}}

open a html modal programmatically in React

I have this two elements a button and a dialog
<dialog className='w-11/12 shadow-none rounded-tl-md rounded-tr-md lg:rounded-lg absolute'>wqdwe</dialog>
<button className=" px-6 py-2 rounded absolute mt-12 ml-12" onClick={} >Click</button>
How can I open the dialog on clicking the button in React
constructor(props) {
super(props);
this.myRef = React.createRef();
}
showModals(){
this.myRef.showModal();
}
componentDidMount() {
//this.showModals()
}
EDIT: I am trying to access the .showModal() method in the dialog according to MDN https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog. How can I do that, I need the dimmed background feature when the modal is opened.
You do not need componentDidMount nor useRef with the state and using the props open of the dialog you can show it conditionally.
first solution using isOpen is the state
class Modal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<dialog style={{width: "80%", height: "80%", marginTop: 10, backgroundColor: '#eee'}}
open={this.props.open}
>
<p>Greetings, one and all!</p>
</dialog>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
};
}
switchModal = (prevState) => {
this.setState((prevState, props) => {
return { isOpen: !prevState.isOpen }
});
}
render() {
return (
<div>
<button onClick={this.switchModal}>
{this.state.isOpen ? 'Close' : 'Open'} Modal
</button>
<br/>
<Modal open={this.state.isOpen}/>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>
second solution using native showModal method. With this method you can use the css property dialog::backdrop.
class Modal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<dialog id='modal' style={{width: "80%", height: "80%", marginTop: 10, backgroundColor: '#eee'}}
>
<p>Greetings, one and all!</p>
<button onClick={this.props.closeModal}>
Close Modal
</button>
</dialog>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
};
}
switchModal = (prevState) => {
this.setState((prevState, props) => {
if(!prevState.isOpen) {
document.getElementById('modal').showModal()
} else {
document.getElementById('modal').close()
}
return { isOpen: !prevState.isOpen }
});
}
render() {
return (
<div>
{!this.state.isOpen && <button onClick={this.switchModal}>
Open Modal
</button>}
<br/>
<Modal
closeModal={this.switchModal}
/>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
dialog {
height: 80%;
width: 80%
}
dialog::backdrop {
background: rgba(255,0,0,.25);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>
You can use the React state API to show and hide components based on actions taken elsewhere in the code.
class MyComponent extends React.Component {
constructor() {
this.state = {
isDialogVisible: false
}
}
handleClick = () => {
this.setState({ isDialogVisible: !this.state.isDialogVisible })
}
render() {
const { isDialogVisible } = this.state
return (
<div>
<Button onClick={this.handleClick}>{isDialogVisible ? 'Hide' : 'Show'} dialog</Button>
{this.state.isDialogVisible && <Dialog />}
</div>
)
}
}

How to make Snackbar open again?

I created a Snackbar component.
import React, { Component } from 'react';
import { Snackbar, IconButton } from '#material-ui/core';
import CloseIcon from '#material-ui/icons/Close';
interface AlertProps {
message: string;
}
interface AlertState {
open: boolean;
}
export default class Alert extends Component<AlertProps, AlertState> {
constructor(props: AlertProps) {
super(props);
this.state = {
open: true
};
this.handleClose = this.handleClose.bind(this);
}
handleClose(event: React.SyntheticEvent | React.MouseEvent, reason?: string) {
if (reason !== 'clickaway') {
this.setState({
open: false
});
}
}
render() {
return (
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
open={this.state.open}
autoHideDuration={6000}
onClose={this.handleClose}
message={this.props.message}
action={
<IconButton
key="close"
color="inherit"
onClick={this.handleClose}
>
<CloseIcon />
</IconButton>
}
/>
)
}
}
I then programmatically add it to a render when an error is encountered while submitting a form.
let alert: ReactNode;
if (this.state.error) {
alert = <Alert message={this.state.error} />;
}
Problem is the Snackbar only opens the first time an error is encountered. If a user submits the same form twice, the Snackbar doesn’t open.
I know it’s because of this.state.open = false which is set by the onClose method, but how can I "reset" this state before the form is submitted again?
One way is you could change your approach a bit and always have Alert rendered, i.e.
<Alert message={this.state.error} open={this.state.open} onClose={()=>{this.setState({open:false})}}/>
Also move the open state variable from Alert's state to its parent. So in Alert use the open value from props always. Now, whenever open is changed in the parent, Alert will re render properly.

Get modal to fire from parent component

Noob question here. How do I fire the toggle component of the Modal from the parent component? I want the modal to open when the button is clicked on the parent component. The button will submit a form and once the form has been submitted I want the modal to fire. I'm trying to get it to fire in function handleSubmit(e)
Child Component: Modal.jsx
class ModalExample extends React.Component {
constructor(props) {
super(props);
this.state = {
modal: false
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal
}));
}
render() {
return (
<div>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<ModalHeader toggle={this.toggle}>Modal title</ModalHeader>
</Modal>
</div>
);
}
}
Path: Parent.jsx
export default function ForgotPassword() {
function handleSubmit(e) {
e.preventDefault();
}
return (
<div className="container h-100">
<ModalExample toggle />
<button onClick={this.handleSubmit}>Open modal</button>
</div>
);
}
You can use refs as follows
export default function ForgotPassword() {
function handleSubmit(e) {
e.preventDefault();
}
return (
<div className="container h-100">
<ModalExample ref={instance => { this.child = instance; }} />
<button onClick={() => { this.child.toggle(); }}>Open modal</button>
</div>
);
}
There might be better ways, but the way I've done it is by pulling the toggle function to the parent class and passing both the function and the state value to the modal in props.
You can then call that props function in your modal to toggle its display, although this will turn your pure component into a stateful component.
Child Component: Modal.jsx
class ModalExample extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Modal isOpen={this.props.modal} toggle={this.props.toggle} className={this.props.className}>
<ModalHeader toggle={this.props.toggle}>Modal title</ModalHeader>
</Modal>
</div>
);
}
}
Parent: Parent.jsx
class ForgotPassword() extends React.Component {
constructor(props) {
super(props);
this.state = {
modal: false
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal
}));
}
return (
<div className="container h-100">
<ModalExample toggle={this.toggle} modal={this.state.modal} />
<button onClick={this.handleSubmit}>Open modal</button>
</div>
);
}

Resources