Search code examples
javascriptreactjsreactstrapreact-modal

reactstrap modal not working properly have to cancel it twice


I have a dropdown menu and inside the menu there is an option Load Plan, when this option is selected a modal should appear. As implemented the modal appears when the option Load Plan is clicked on, but when you cancel the modal it dismisses but appears again. When you hit cancel the second time it permanently dismisses. The same functionality happens when I try to use the file up-loader option on the modal as well. After I click the upload button the file explorer opens when I select the file, the file explorer closes but doesn't register to the modal unless I do it a second time.

Here is the navigational bar containing the dropdown menu:

import React, {Component} from "react";
import {Navbar, NavbarBrand, Nav, 
NavItem, DropdownToggle, 
Dropdown, DropdownMenu, 
DropdownItem,
UncontrolledDropdown, Row, Col, 
Container, Input} from "reactstrap";
import PlanModal from './loadModal';

class Topbar extends Component {
    constructor(props){
        super(props);
        this.state = {
            dropdownOpen: false,
            f_settings: true,
            f_help: true,
            isModalOpen: false
        };

        this.showModal = this.showModal.bind(this);
        this.toggle = this.toggle.bind(this);
    }

    toggle() {
        this.setState({
             isModalOpen: !this.state.isModalOpen
        })
    }

    showModal() {
        this.setState({
            isModalOpen:true
        })
    }



    render() {
        return (
            <Container fluid={true}>
                <Navbar color="light" light expand="md">
                <Row>
                    <NavbarBrand> Raytheon<NavbarBrand>
                    <Nav navbar>
                    <Col xs="8">
                        <UncontrolledDropdown>
                        <DropdownToggle nav caret>
                        File
                        </DropdownToggle>
                        <DropdownMenu right>
                             <DropdownItem onClick={this.changeValue}>
                             File
                             </DropdownItem>
                             <PlanModal isOpen={this.state.isModalOpen} toggle={this.toggle}/>
                        </DropdownMenu>
                        </UncontrolledDropdown>
                    </Col>
                </Row>
                </Navbar>
          </Container>
        )

    }


}

This is the modal component


class PlanModal extends Component{
    constructor(props){
        super(props);
        this.state = {
            selectedFile: null
        };
    }

    handleFile(e) {
        e.stopPropagation();
        this.setState({
            selectedFile: event.target.files[0]
        })
    }


    uploadFile(file) {
        ...
    }


    render() {
        return(
            <div>
            <Button color="transparent" onClick={this.props.toggle}>Load Plan</Button>
            <Modal isOpen={this.props.isOpen}>
                <ModalHeader toggle={this.props.toggle}>Nav Plan</ModalHeader>
                <ModalBody>
                    File In use:
                    <Input type="file" id= "file" onChange={e=>this.handleFile(e)/>
                </ModalBody>
                <ModalFooter>
                    <Button color="primary" onClick={file=> this.uploadFile(file)}>Run</Button>
                    <Button color="secondary" onClick={this.props.toggle}>Cancel</Button>
                </ModalFooter>
            </Modal
            </div>
        )

    }

}

export default PlanModal;

Any help would be greatly appreciated!


Solution

  • This happens because of the 'UncontrolledDropdown' component. When you toggle the modal, the dropdown is still opened and when you click on the modal, then the dropdown closes forcing every child to update. And well, the modal is a child of that dropdown, so what you gotta do is. Make it controlled and close it before opening the modal or put the modal on a more global scope. Like this:

    import React, { Component } from "react";
    import {
      Navbar,
      Button,
      NavbarBrand,
      Nav,
      NavItem,
      DropdownToggle,
      Dropdown,
      DropdownMenu,
      DropdownItem,
      UncontrolledDropdown,
      Row,
      Col,
      Container,
      Input
    } from "reactstrap";
    import PlanModal from "./Plan";
    
    export default class Topbar extends Component {
      constructor(props) {
        super(props);
        this.state = {
          dropdownOpen: false,
          f_settings: true,
          f_help: true,
          isModalOpen: false
        };
    
        this.showModal = this.showModal.bind(this);
        this.toggle = this.toggle.bind(this);
      }
    
      toggle() {
        this.setState(
          {
            isModalOpen: !this.state.isModalOpen
          },
          () => {
            console.log(this.state.isModalOpen);
          }
        );
      }
    
      showModal() {
        this.setState({
          isModalOpen: true
        });
      }
    
      changeValue() {}
    
      render() {
        return (
          <Container fluid={true}>
            <Navbar color="light" light expand="md">
              <Row>
                <NavbarBrand> Raytheon</NavbarBrand>
                <Nav navbar>
                  <Col xs="8">
                    <UncontrolledDropdown>
                      <DropdownToggle nav caret>
                        File
                      </DropdownToggle>
                      <DropdownMenu right>
                        <DropdownItem onClick={this.changeValue}>File</DropdownItem>
                        <Button color="transparent" onClick={this.toggle}>
                          Load Plan
                        </Button>
                      </DropdownMenu>
                    </UncontrolledDropdown>
                  </Col>
                </Nav>
              </Row>
            </Navbar>
            <PlanModal isOpen={this.state.isModalOpen} toggle={this.toggle} />
          </Container>
        );
      }
    }
    
    

    I took the button out of the component and put the modal as a child of 'Container' instead of 'DropdownItem'.