Bootstrap modal didn't close while clicking outside of modal in React - reactjs

I used a react-bootstrap modal to show notification in React. It works fine but it didn't close when I click outside of the modal.
Modal code
import React from "react";
import ReactDom from 'react-dom';
import Modal from "react-bootstrap/Modal";
import ModalBody from "react-bootstrap/ModalBody";
import ModalHeader from "react-bootstrap/ModalHeader";
import ModalFooter from "react-bootstrap/ModalFooter";
import ModalTitle from "react-bootstrap/ModalTitle";
import 'bootstrap/dist/css/bootstrap.css';
class ForgetPassword extends React.Component{
constructor(props)
{
super(props);
this.state={
modalIsOpen:true
}
}
render()
{
return (
<Modal show={this.state.modalIsOpen}>
<ModalHeader>
<ModalTitle>Hi</ModalTitle>
</ModalHeader>
<ModalBody>asdfasdf</ModalBody>
<ModalFooter>This is the footer</ModalFooter>
</Modal>
);
}
}
export default ForgetPassword;

You don't have toggle set on the Modal component. You need to add the toggle prop to <Modal>, giving it a function, which when triggered, will toggle the value of the IsOpen in prop.
import React from "react";
import Modal from "react-bootstrap/Modal";
import ModalBody from "react-bootstrap/ModalBody";
import ModalHeader from "react-bootstrap/ModalHeader";
import ModalFooter from "react-bootstrap/ModalFooter";
import ModalTitle from "react-bootstrap/ModalTitle";
import 'bootstrap/dist/css/bootstrap.css';
class ForgetPassword extends React.Component{
state = {
modalIsOpen: true
}
toggleModal = () => {
this.setState(prevState => ({
modalIsOpen: !prevState.modalIsOpen
}));
};
render() {
return (
<Modal show={this.state.modalIsOpen} onHide={this.toggleModal}>
<ModalHeader>
<ModalTitle>Hi</ModalTitle>
</ModalHeader>
<ModalBody>asdfasdf</ModalBody>
<ModalFooter>This is the footer</ModalFooter>
</Modal>
);
}
}
export default ForgetPassword;
Source

The bootstrap react docs make reference to the onHide prop that should be on the modal - A callback fired when the header closeButton or non-static backdrop is clicked. Required if either are specified.
You will want to use this to set the show modal state as false, probably through a function.

Related

how to call a different js file output to another js file by using onclick button in react

the given are the files i created as js file.....clicking button in the same file which I commented the
button tag in output.js that is working fine and if i change the button in different page that is the confusion
output.js
import React, {Component} from 'react'
import { Modal, Button } from 'react-bootstrap'
class Threed extends Component {
constructor(){
super()
this.state ={show:false}
}
threedModal(){
this.setState({show:!this.state.show})
}
render() {
return (
<div>
{/*<Button onClick= {() => {this.threedModal()}}>
rajesh
</Button>*/}
<Modal show={this.state.show} onHide={() => this.handleModal()}>
<Modal.Header closeButton>MY popup</Modal.Header>
<Modal.Body>Rajesh modal done</Modal.Body>
<Modal.Footer><Button onClick= {() => {this.handleModal()}}> close </Button></Modal.Footer>
</Modal>
</div>
)
}
}
export default Threed
home.js
import React, {Component} from 'react'
import { Modal, Button } from 'react-bootstrap'
import threed from './output.js'
class Threed extends Component {
constructor(){
super()
this.state ={show:false}
}
threedModal(){
this.setState({show:!this.state.show})
}
render() {
return (
<div>
<Button onClick= {() => {this.threedModal()}}>
rajesh
</Button>
</div>
)
}
}
export default Threed
I want to show while clicking home.js button and show the modal popup window......
here my confusion is how to get that fuction by clicking button of Home.js
Please forward the value to modal.
Home.js
import Threed from './output.js'
class Home extends Component {
...
< Threed show={this.state.show} />
Threed.js
<Modal show={this.props.show} onHide={() => this.handleModal()}>

Why Enzyme test unworking in React?

I need to test Button component
it's Button :
import React from "react";
import './Button.css'
const Button = props => {
return(
<button className={"Button"}
onClick={props.onClick}
disabled={props.disabled}
>
{props.children}
</button>
)
}
export default Button
It's my Button.test.js:
import React from 'react';
import {shallow} from 'enzyme';
import Button from "./Button";
it('has a title class', () => {
const wrapper = shallow(<Button/>);
expect(wrapper.hasClass('Button')).to.equal(true);
I'm add enzyme to react. In the console I has an error:
enter image description here
tell me how to solve the problem, i'm new in React.
You need to call hasClass on the button element instead of the wrapper:
expect(wrapper.find('button').hasClass('Button')).to.equal(true);

Trying to create a toggle function to set the state of 2 buttons from disabled to enabled based on an onClick event attached to a third button

I have a set of 3 buttons where I need to set the initial state for two buttons as disabled and then create an onClick event for a third button that would enable both buttons when clicked. I'm thinking of setting the disabled attribute in state and then creating the function for onClick that would target the state of both buttons and set it to false. My current code is below, any ideas on how to achieve this?
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Button } from 'antd';
import "antd/dist/antd.css";
import './style.css';
class App extends Component {
constructor() {
super();
this.state = {
disabled: undefined
};
}
toggleSwitch(){
alert("you clicked the switch");
}
render() {
return (
<div>
<Button disabled={true}>Modify Docs</Button>
<Button disabled={true}>Upload Docs</Button>
<Button onClick={this.toggleSwitch}>Unlock Quote</Button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
You're almost there.
In your render method, you've set disabled={true} which means that it will permanently stay true instead of checking the value of the disabled property in state.
The toggle method should simply negate the previous value of disabled.
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Button } from 'antd';
import "antd/dist/antd.css";
import './style.css';
class App extends Component {
state = {
disabled: true,
};
toggleSwitch() {
// when toggling, we just negate the previous value
this.setState(previousState => ({
disabled: !previousState.disabled,
}))
}
render() {
// Buttons will use the same value from state
// to check if they should be disabled
const { disabled } = this.state;
// instead of setting disabled={true}, reference the disabled
// property from state
return (
<div>
<Button disabled={disabled}>Modify Docs</Button>
<Button disabled={disabled}>Upload Docs</Button>
{/* we set the text of the button depending on the value of disabled */}
<Button onClick={this.toggleSwitch}>
{disabled ? 'Unlock Quote' : 'Lock Quote'}
</Button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Also, consider using a toggle component of sorts instead of the third button for better user experience.

ReactComponent Button value won't render on my react app

I've got a simple React App going on. My index.js file looks, of course, like this:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
Going deeper, my App.js file declares an App extends Compoennt class, which contains my to-be-rendered elements and their functions:
import React, { Component } from "react";
import logo from "./SmartTransit_logo.png";
import MyButton from "./components/MyButton";
import "./App.css";
import { isWallet, helloWorld } from "./services/neo-service";
class App extends Component {
state = {
inputValue: ""
};
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Smart Transit Live Demo</h1>
</header>
<div style={{ width: 500, margin: "auto", marginTop: 10 }}>
<MyButton
buttonText="My Button"
onClick={ params => {helloWorld();}}
/>
</div>
</div>
);
}
}
export default App;
And the declaration of MyButton from /components/MyButton:
import React, { Component } from "react";
import PropTypes from "prop-types";
class MyButton extends Component {
render() {
return (
<button className="MyButton"
value = {this.props.buttonText}
>
{this.props.children}
</button>
);
}
}
MyButton.propTypes = {
buttonText: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};
export default MyButton;
Finally, the declaration for helloWorld() is done like so (NOTE: neon-js is an npm package I'm using):
import { wallet } from "#cityofzion/neon-js";
export function isWallet(address) {
console.log(wallet.isAddress(address));
return wallet.isAddress(address);
}
export function helloWorld() {
console.log("Hello world");
return 1;
}
My problem is that the resulting Button doesn't get its value text rendered, and although it gets the CSS code for it just fine, it appears empty!
Not only that, but pressing it doesn't log a "Hello World" in the console, as it should, so it's even disconnected from its onClick function.
Any idea on what I'm doing wrong?
Buttons don't receive a "value" prop. The text inside of the button element is what gives it its text.
The button does appear to accept children to use as button text, but no children is actually being passed down to it. this.props.children is the content between JSX tags when the component is rendered.
React doesn't add the event handlers to elements automatically. You have to pass them along yourself in order for them to be properly triggered.
With that in mind, here's how you should render your button in App:
<MyButton onClick={() => helloWorld()}>
My Button
</MyButton>
And here's how MyButton's code should look:
class MyButton extends Component {
render() {
return (
<button className="MyButton" onClick={this.props.onClick}>
{this.props.children}
</button>
)
}
}
As you can see, the buttonText prop is no longer required; that's what the children prop is for.
You need to define super(props) in class constructor when you are going to use this.props
constructor(props) {
super(props);
}
Define this in MyButton component.
The problem is, you are not calling onClick method from mybutton component and button take it's value between it's opening and closing tag.
Use this code:
this.props.onClick()}> {this.props.buttonText}

Watching state from child component React with Material UI

New to React. Just using create-react-app and Material UI, nothing else.
Coming from an Angular background.
I cannot communicate from a sibling component to open the sidebar.
I'm separating each part into their own files.
I can get the open button in the Header to talk to the parent App, but cannot get the parent App to communicate with the child LeftSidebar.
Header Component
import React, {Component} from 'react';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import NavigationMenu from 'material-ui/svg-icons/navigation/menu';
class Header extends Component {
openLeftBar = () => {
// calls parent method
this.props.onOpenLeftBar();
}
render() {
return (
<AppBar iconElementLeft={
<IconButton onClick={this.openLeftBar}>
<NavigationMenu />
</IconButton>
}
/>
);
}
}
export default Header;
App Component -- receives event from Header, but unsure how to pass dynamic 'watcher' down to LeftSidebar Component
import React, { Component } from 'react';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import RaisedButton from 'material-ui/RaisedButton';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
// components
import Header from './Header/Header';
import Body from './Body/Body';
import Footer from './Footer/Footer';
import LeftSidebar from './LeftSidebar/LeftSidebar';
class App extends Component {
constructor() {
super() // gives component context of this instead of parent this
this.state = {
leftBarOpen : false
}
}
notifyOpen = () => {
console.log('opened') // works
this.setState({leftBarOpen: true});
/*** need to pass down to child component and $watch somehow... ***/
}
render() {
return (
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div className="App">
<Header onOpenLeftBar={this.notifyOpen} />
<Body />
<LeftSidebar listenForOpen={this.state.leftBarOpen} />
<Footer />
</div>
</MuiThemeProvider>
);
}
}
export default App;
LeftSidebar Component - cannot get it to listen to parent App component - Angular would use $scope.$watch or $onChanges
// LeftSidebar
import React, { Component } from 'react';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
import IconButton from 'material-ui/IconButton';
import NavigationClose from 'material-ui/svg-icons/navigation/close';
class LeftNavBar extends Component {
/** unsure if necessary here **/
constructor(props, state) {
super(props, state)
this.state = {
leftBarOpen : this.props.leftBarOpen
}
}
/** closing functionality works **/
close = () => {
this.setState({leftBarOpen: false});
}
render() {
return (
<Drawer open={this.state.leftBarOpen}>
<IconButton onClick={this.close}>
<NavigationClose />
</IconButton>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
);
}
}
export default LeftSidebar;
Free your mind of concepts like "watchers". In React there is only state and props. When a component's state changes via this.setState(..) it will update all of its children in render.
Your code is suffering from a typical anti-pattern of duplicating state. If both the header and the sibling components want to access or update the same piece of state, then they belong in a common ancestor (App, in your case) and no where else.
(some stuff removed / renamed for brevity)
class App extends Component {
// don't need `constructor` can just apply initial state here
state = { leftBarOpen: false }
// probably want 'toggle', but for demo purposes, have two methods
open = () => {
this.setState({ leftBarOpen: true })
}
close = () => {
this.setState({ leftBarOpen: false })
}
render() {
return (
<div className="App">
<Header onOpenLeftBar={this.open} />
<LeftSidebar
closeLeftBar={this.close}
leftBarOpen={this.state.leftBarOpen}
/>
</div>
)
}
}
Now Header and LeftSidebar do not need to be classes at all, and simply react to props, and call prop functions.
const LeftSideBar = props => (
<Drawer open={props.leftBarOpen}>
<IconButton onClick={props.closeLeftBar}>
<NavigationClose />
</IconButton>
</Drawer>
)
Now anytime the state in App changes, no matter who initiated the change, your LeftSideBar will react appropriately since it only knows the most recent props
Once you set the leftBarOpen prop as internal state of LeftNavBar you can't modify it externally anymore as you only read the prop in the constructor which only run once when the component initialize it self.
You can use the componentWillReceiveProps life cycle method and update the state respectively when a new prop is received.
That being said, i don't think a Drawer should be responsible for being closed or opened, but should be responsible on how it looks or what it does when its closed or opened.
A drawer can't close or open it self, same as a light-Ball can't turn it self on or off but a switch / button can and should.
Here is a small example to illustrate my point:
const LightBall = ({ on }) => {
return (
<div>{`The light is ${on ? 'On' : 'Off'}`}</div>
);
}
const MySwitch = ({ onClick, on }) => {
return (
<button onClick={onClick}>{`Turn the light ${!on ? 'On' : 'Off'}`}</button>
)
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
lightOn: false
};
}
toggleLight = () => this.setState({ lightOn: !this.state.lightOn });
render() {
const { lightOn } = this.state;
return (
<div>
<MySwitch onClick={this.toggleLight} on={lightOn} />
<LightBall on={lightOn} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Resources