Charles L.
Charles L.

Reputation: 1970

React show toggle showing all children

Im using react.js and im trying to have a <ul> with each <li> having a child <ul>. When an icon in the <li> is clicked Im trying to show its child <ul>. The current way I have it its showing ALL the <li>'s children instead of just its own corresponding child.

    const FooterMenu = (props) => {

    const { menuName } = props;
    const [menu, setMenu] = useState([]);
    const [showDetails, setShowDetails] = useState(false);

    useEffect(() => {
        if (menuName) {
            axios.get(``)
                .then(response => {
                   setMenu(response.data);
                }).catch(error => {
                    console.log('[Page] error', error); //TO-DO: remove before prod deployment
                    //TO-DO: add redirect to error page
                })
        }
        
    }, [menuName]);

    return (
        <ul>
            { menu.map(row => {
                return (
                    <li className="footer-menu-icon footer-menu-item">
                        <i className={`fas showSubLinks ${row.SubMenus.length >= 1 ? (showDetails ? 'fa-minus' : 'fa-plus') : 'fa-angle-right'}`} onClick={() => setShowDetails(() => !showDetails)}></i>
                        <a href={row.MenuLink} target={row.LinkTarget ? row.LinkTarget : '_self'}>{row.MenuText}</a>
                        {row.SubMenus.length >= 1 && showDetails  ? (
                            <ul className="subMenu-items">
                                {
                                    row.SubMenus.map(row => {
                                        return (
                                            <li>
                                                <a href={row.MenuLink} target={(row.LinkTarget) ? row.LinkTarget : '_self'}>{row.MenuText}</a>
                                            </li>
                                        )
                                    })
                                }
                            </ul>
                        ) : (
                            <></>
                        )}
                    </li>
                )
            })}
        </ul>
    );
};

export default FooterMenu;

I know the showDetails is to blame but cant seem to wrap my head around how to do this

enter image description here

enter image description here

Upvotes: 0

Views: 49

Answers (2)

Guruparan Giritharan
Guruparan Giritharan

Reputation: 16334

You can handle the the showDetails in the menu array itself as a property like below, when the menu is loaded it will have the default value which is false and after that the buttons would toggle it to true and false

const Menu = () => {
  const [menu, setMenu] = useState([
    {
      MenuText: "Submenu",
      SubMenus: [
        {
          MenuLink: "#",
          MenuText: "Submenu"
        }
      ]
    },

    {
      MenuText: "Submenu1",
      SubMenus: [
        {
          MenuLink: "#",
          MenuText: "Submenu"
        }
      ]
    }
  ]);

  return (
    <ul>
      {menu.map((row, i) => {
        return (
          <li className="footer-menu-icon footer-menu-item">
            <i
              className={`fas showSubLinks ${
                row.SubMenus.length >= 1
                  ? row.showDetails
                    ? "fa-minus"
                    : "fa-plus"
                  : "fa-angle-right"
              }`}
              onClick={() => {
                const updatedMenu = [...menu];
                updatedMenu[i].showDetails = !updatedMenu[i].showDetails;
                setMenu(updatedMenu);
              }}
            ></i>
            <a
              href={row.MenuLink}
              target={row.LinkTarget ? row.LinkTarget : "_self"}
            >
              {row.MenuText}
            </a>
            {row.SubMenus.length >= 1 && row.showDetails ? (
              <ul className="subMenu-items">
                {row.SubMenus.map((row) => {
                  return (
                    <li>
                      <a
                        href={row.MenuLink}
                        target={row.LinkTarget ? row.LinkTarget : "_self"}
                      >
                        {row.MenuText}
                      </a>
                    </li>
                  );
                })}
              </ul>
            ) : (
              <></>
            )}
          </li>
        );
      })}
    </ul>
  );
};

Upvotes: 1

Alexey  Baguk
Alexey Baguk

Reputation: 168

Just separate submenu to another component with own showDetails state.

{row.SubMenus.length >= 1 &&  (
   <ul className="subMenu-items">
     {
      row.SubMenus.map(row => <SubMenuComponent />)
     }
   </ul>
)}

Upvotes: 0

Related Questions