1

When I click on a single dropdown menu link in the navigation bar, all the dropdown menu links also show or display. How do I fix this by letting only one dropdown menu link show?

I have tried changing the id value that points to aria-labelledby

This is the state of my app

      state = {
        dropDown: false
      };


      handleDropdown = e => {
            this.setState({ dropDown: !this.state.dropDown });
        };

Inside the render function

      render() {
        const { dropDown } = this.state;

      /*Conditional statement to select a class base on the state*/

      const dropMenu = dropDown ? 'dropdown-menu show' : 'dropdown-menu';

      /*The two dropdown menu list the displays(both) even when one is clicked*/

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="navbarDropdown"
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={dropMenu} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="navbarDropdown"
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={dropMenu} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>
      };

2
  • Just as an alternative to you hand writing this, you should make use of someone else's code. reactstrap.github.io/components/navs This has all the Bootstrap 4 menu's pre-existing. Commented Apr 24, 2019 at 12:32
  • Thanks for the resource. But in this project, I want to use Bootstrap as a dependency rather than using a Bootstrap package like react-bootstrap Commented Apr 24, 2019 at 13:19

2 Answers 2

1

because you only 1 state to handle show and hide the dropdown menu. try doing it like this :

state = {
  dropDown: {
    link1: false,
    link2: false,
  }
}

handleDropdown = e => {
  const { id } = e.target;

  this.setState(prevState => ({
    dropDown : {
      ...prevState.dropDown,
      [id]: !prevState.dropDown[id],
    }
  }));
}

render() {

const { dropDown } = this.state;

      /*Conditional statement to select a class base on the state*/

      const dropMenu = dropDown ? 'dropdown-menu show' : 'dropdown-menu';

      /*The two dropdown menu list the displays(both) even when one is clicked*/

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="link1" // name your id same as the variable from state dropDown
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={`dropdown-menu ${dropDown.link1 ? 'show' : ''}`} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>

    <li className="nav-item dropdown">
                      <Link
                        onClick={this.handleDropdown}
                        className="nav-link dropdown-toggle"
                        href="#"
                        id="link2" // name your id same as the variable from state dropDown
                        role="button"
                        data-toggle="dropdown"
                        aria-haspopup="true"
                        aria-expanded="false"
                      >
                        Dropdown
                      </Link>
                      <div className={`dropdown-menu ${dropDown.link2 ? 'show' : ''}`} aria-labelledby="navbarDropdown">
                        <Link className="dropdown-item" to="#">
                          Action
                        </Link>
                        <Link className="dropdown-item" to="#">
                          Another action
                        </Link>
                        <div className="dropdown-divider" />
                        <Link className="dropdown-item" to="#">
                          Something else here
                        </Link>
                      </div>
                    </li>
}

hope it works.

0
1

Updated code

Change the state variable as follows:

state = {
  dropDownState: [false, false]
};

As you have just have two li > div the array contains two elements, if menu items increase, increase them as well.

Then the div's would look like

<div className={dropMenu[0]} aria-labelledby="navbarDropdown"> and <div className={dropMenu[1]} aria-labelledby="navbarDropdown">

Each of the function bindings would look like

onClick={() => this.handleDropdown(0)}
onClick={() => this.handleDropdown(1)}

The actual function would then change to

handleDropdown = (menuIndex) => {
   let newMenuState = this.state.dropDownState.map((val, index) => {
       if(index === menuIndex) {
           return !val
       } else return val
   });

  this.setState({ dropDownState: newMenuState })
};

Please note I haven't run the code on my end, but you should get the idea.

Old Answer

Instead of calling the function, bind the value to the function:

Change

onClick={this.handleDropdown}

To

onClick={() => this.handleDropdown()}

7
  • I tried binding the method, but it still called the two dropdown menu links Commented Apr 24, 2019 at 11:44
  • Where are you using the const const dropMenu? I don't see it in your code anywhere else. Don't you need to use that as the class of the div inside each li? Not only that, a single state variable decides the class which then affects all the divs inside each lis (after applying the const as the class for the div). You need to make it dynamic using array. Each array element would hold the state for each li > div. Commented Apr 24, 2019 at 12:09
  • Ouch, sorry. I just edited the code. Exactly, I used the dropMenu on the div inside the li and the problem still exists. Please, I don't get the path where I need to make it dynamic. Because const dropMenu holds the class depending on the state of dropDown in the render function. Thanks for your time. Commented Apr 24, 2019 at 12:19
  • I'm getting close to the solution. I console.log(dropMenu[0]) which you used in the div element in your updated code and got the first letter of the class which was d (ie. dropdown-menu). Commented Apr 24, 2019 at 13:17
  • Change <div className={dropMenu[0]} aria-labelledby="navbarDropdown"> to <div className={this.state.dropDownState[0]} aria-labelledby="navbarDropdown">, sorry I missed that part. Basically use the array element from the new state variable. Commented Apr 24, 2019 at 13:22

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.