Hema Nandagopal
Hema Nandagopal

Reputation: 678

show items based on array content

I have a header menu for which I've submenu items. For example in the below the first item alone has submenu. I've to show the submenu on hovering only on the header menu which as submenu.But I'm getting the submenu on hovering all the header menu.I'm using tailwindcss for this and below is the code snippet.

headerdata.json

{  
    "headerData": [
        {"text":"Home Applicances", "url":"homeappli","submenu":[
            {
            "submenuText":"Television",
            "url":""
        }, 
        {
            "submenuText":"Fridge",
            "url":""
        }, 
        {
            "submenuText":"Washing Machine",
            "url":""
        }
        ]},  
        {"text":"Mobiles & Accessories", "url":"mobile"}, 
        {"text":"Discount Combos", "url":"disc"},  
        {"text":"Offers", "url":"offers"}  
    ]
       
}  

and JS :

   import React, { useState } from "react";
// import './Header.styles';
import logo from "../../images/logo-dark.png";
import FavoriteBorderIcon from "@material-ui/icons/FavoriteBorder";
import ShoppingCartIcon from "@material-ui/icons/ShoppingCart";
import SearchIcon from "@material-ui/icons/Search";
import Avatar from "@material-ui/core/Avatar";
import LoginModal from "../Modal/LoginModal";
import headerData from "../../data/headerData.json";

function Header() {
  const [openSearch, setOpensearch] = useState(false);
  const [isUserLogged, setIsUserLogged] = useState(false);
  const [showSubmenu , setShowSubmenu] = useState(false);

  const handleSearch = () => {
    setOpensearch(!openSearch);
  };

  const handleLogin = () => {
    // Checking whether used loggedin using local storage logic
    setIsUserLogged(true);
    // return <LoginModal />
  };

  const closeModal = () => {
    setIsUserLogged(false);
  };

  return (
    <div className="fixed md:px-8 px-8 w-full z-10 bg-white shadow-md">
      <div className="flex lg:justify-around md:my-3  md:flex-row sm:flex-row ">
        <div className="flex justify-center items-center w-full">
          <img src={logo} className="h-30 md:h-30 " alt="Ansar_logo" />
        </div>

        <div className="flex text-lg cursor-pointer h-10" onClick={handleLogin}>
          <div className="px-2 whitespace-no-wrap flex items-center">
            Sign In
          </div>
          <Avatar />
        </div>
        {isUserLogged && <LoginModal handleClose={closeModal} />}
      </div>
      <div className="flex lg:justify-around md:mb-6 md:flex-row sm:flex-row h-4">
        <div className="flex justify-center items-center w-4/5">
          {headerData?.headerData?.map((data) => {
            return (
              <div 
              onMouseEnter={() => setShowSubmenu(true)}
        onMouseLeave={() => setShowSubmenu(false)}
              
              className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900  uppercase ">
                {data.text}
              </div>
            );
          })}
        </div>
        {showSubmenu  && <div>
        {headerData?.headerData[0].submenu.map((data) => {
            return (
              <li className="px-5 py-2
              cursor-pointer relative  font-medium bg-red-800 hover:text-green-900  uppercase  list-none">
                {data.submenuText}
              </li>
            );
          })}
          
        </div>
}

        <div className="flex justify-end w-1/5">
          <div className="pr-2 flex">
            {openSearch && (
              <input
                type="search"
                className=" w-auto border-b-2 px-8 py-4 -mt-3 border-black outline-none"
                placeholder="Search product...."
              />
            )}
            <SearchIcon onClick={handleSearch} className="cursor-pointer" />
          </div>

          <div className="pr-2 flex flex-col place-items-center ">
            <FavoriteBorderIcon className="cursor-pointer" />
          </div>
          <div className="flex flex-col place-items-center">
            <ShoppingCartIcon className="cursor-pointer" />
          </div>
        </div>
      </div>
    </div>
  );
}

export default Header;

Upvotes: 0

Views: 57

Answers (2)

apena
apena

Reputation: 2321

You were not conditionally setting the onMouseOver callback. Instead you were setting state which was using the same submenu for every menu item.

Here is a simplified version of the fix you can mess around with:

Edit focused-framework-p9ujl

json file:

{
  "navbar": [
    {
      "text": "Home Applicances",
      "url": "homeappli",
      "submenu": [
        {
          "submenuText": "Television",
          "url": ""
        },
        {
          "submenuText": "Fridge",
          "url": ""
        },
        {
          "submenuText": "Washing Machine",
          "url": ""
        }
      ]
    },
    { "text": "Mobiles & Accessories", "url": "mobile" },
    { "text": "Discount Combos", "url": "disc" },
    { "text": "Offers", "url": "offers" }
  ]
}

Javascript file (simplified)

import React, { useState } from "react";
import ReactDOM from "react-dom";

import headerData from "./headerData.json";

import "./styles.css";

function App() {
  const [menuIndex, setMenuIndex] = useState(-1);
  return (
    <div id="navbarHolder">
      {headerData.navbar.map((item, index) => {
        return (
          <div
            key={index}
            onMouseOver={
              item.hasOwnProperty("submenu")
                ? () => setMenuIndex(index)
                : () => setMenuIndex(-1)
            }
          >
            {item.text}
          </div>
        );
      })}
      {menuIndex > -1 && (
        <div>
          {headerData.navbar[menuIndex].submenu.map((item) => {
            return <li>{item.submenuText}</li>;
          })}
        </div>
      )}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Upvotes: 1

Itamar
Itamar

Reputation: 1634

So you had two bugs here:

  1. you always added the hover events
  2. You always show the same submenu

Here is a fixed example: and also CodeSandbox

import React, { useState } from "react";
import "./styles.css";

const data = {
  headerData: [
    {
      text: "Home Applicances",
      url: "homeappli",
      submenu: [
        {
          submenuText: "Television",
          url: ""
        },
        {
          submenuText: "Fridge",
          url: ""
        },
        {
          submenuText: "Washing Machine",
          url: ""
        }
      ]
    },
    { text: "Mobiles & Accessories", url: "mobile" },
    { text: "Discount Combos", url: "disc" },
    { text: "Offers", url: "offers" }
  ]
};
export default function App() {
  const [currentSubment, setCurrentSubmenu] = useState(-1);
  return (
    <div className="flex lg:justify-around md:mb-6 md:flex-row sm:flex-row h-4">
      <div className="flex justify-center items-center w-4/5">
        {data.headerData.map((data, index) => {
          if (data.submenu) {
            return (
              <div
                onMouseEnter={() => setCurrentSubmenu(index)}
                onMouseLeave={() => setCurrentSubmenu(-1)}
                className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900  uppercase "
              >
                {data.text}
              </div>
            );
          }
          return (
            <div className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900  uppercase ">
              {data.text}
            </div>
          );
        })}
      </div>
      {currentSubment > -1 && (
        <div>
          {data.headerData[currentSubment].submenu.map((data) => {
            return (
              <li
                className="px-5 py-2
                cursor-pointer relative  font-medium bg-red-800 hover:text-green-900  uppercase  list-none"
              >
                {data.submenuText}
              </li>
            );
          })}
        </div>
      )}
    </div>
  );
}

Upvotes: 1

Related Questions