0

I have a problem where I have a menu with parent menu items and if there is a sub menu on click it toggles that nested UL.

Now, I have 2 and the problem is when I place it inside the forEach it toggles both instead of the current clicked parent item submenu.

How can I tell JS to only toggle the div from the clicked element only?

PHP in WordPress:

<?php
function main_navigation() {
    $menu_name      = 'main_menu';
    $locations      = get_nav_menu_locations();
    $menu           = wp_get_nav_menu_object( $locations[ $menu_name ] );
    $menu_items     = wp_get_nav_menu_items( $menu->term_id, array( 'order' => 'ASC' ) );
    $count          = 0;
    $sub_menu       = false;
?>

<ul class="header__list">
    <?php
    foreach( $menu_items as $item ):

        $link           = $item->url;
        $title          = $item->title;
        $class          = $item->classes[0];

        // item does not have a parent so menu_item_parent equals 0 (false)
        if ( !$item->menu_item_parent ):

        // save this id for later comparison with sub-menu items
        $parent_id = $item->ID;
    ?>

    <li class="header__item">
        <a href="<?php echo $link; ?>" class="header__link <?php echo $class ?>"><?php echo $title; ?></a>

        <?php endif; ?>

        <?php if ( $parent_id == $item->menu_item_parent ): ?>

            <?php if ( !$sub_menu ): $sub_menu = true; ?>
            <ul class="header__sub-list" aria-role="header-sublist">
            <?php endif; ?>

                <li class="header__sub-item">
                    <a href="<?php echo $link; ?>" class="header__sub-link"><?php echo $title; ?></a>
                </li>

            <?php if ( $menu_items[ $count + 1 ]->menu_item_parent != $parent_id && $sub_menu ): ?>
            </ul>
            <?php $sub_menu = false; endif; ?>

        <?php endif; ?>
    </li>

<?php
$count++;
endforeach;
?>

</ul>
<?php
}

JS:

const headerSubLists = document.querySelectorAll('.header__link-sub');

headerSubLists.forEach((headerSubList) => {
    const headerSubMenu = document.querySelectorAll(
        '[aria-role="header-sublist"]'
    );

    const openSubMenu = (e) => {
        e.preventDefault();

        headerSubMenu.forEach((menu) => {
            menu.classList.toggle('is-open');
        });
    };

    headerSubList.addEventListener('click', openSubMenu);
});
Galanthus
  • 1,958
  • 3
  • 14
  • 35
  • 2
    [Validate your HTML](//validator.nu). Your structure is invalid. See [Proper way to make HTML nested list?](/q/5899337/4642212). I’d start with that before worrying about events. – Sebastian Simon Mar 01 '23 at 12:58
  • Thank you but that is not my question. @SebastianSimon or the help I need. – Galanthus Mar 01 '23 at 13:00

1 Answers1

1

First change your js like so :

const headerSubLists = document.querySelectorAll('.header__link-sub');

headerSubLists.forEach((headerSubList) => {
    const parentItem = headerSubList.closest('.header__item');
    const subMenuId = parentItem.dataset.subMenu;
    const subMenu = document.getElementById(subMenuId);

    const openSubMenu = (e) => {
        e.preventDefault();
        subMenu.classList.toggle('is-open');
    };

    headerSubList.addEventListener('click', openSubMenu);
});

Then in your php file add the data attribute to the parent item when you create the sub-menu :

<?php if ( !$sub_menu ): $sub_menu = true; ?>
    <ul class="header__sub-list" aria-role="header-sublist" id="sub-menu-<?php echo $parent_id ?>" data-sub-menu="sub-menu-<?php echo $parent_id ?>">
<?php endif; ?>
Baki
  • 213
  • 8