0

I'm trying to convert some old jQuery code that manages the expanded/collapsed state of items in a navigation menu to pure JS and I've hit a roadblock.

HTML menu code:

<nav class="main-navigation">
    <ul class="menu">
        <li class="menu-item">
            <a href="#">Item 1</a>
            <button class="dropdown-toggle" aria-expanded="false">
                <svg class="svg-icon"></svg>
                <span class="screen-reader-text">Expand submenu</span>
            </button>
            <ul class="sub-menu">
                <li class="menu-item">
                    <a href="/item-a/">Item a</a>
                </li>
                <li class="menu-item">
                    <a href="/item-b/">Item b</a>
                </li>
                <li class="menu-item">
                    <a href="/item-c/">Item c</a>
                </li>
                
                ...

jQuery code:

var container = $( '.main-navigation' );
container.find( '.dropdown-toggle' ).on( 'click', function( e ) {
    var _this = $( this );
    e.preventDefault();
    
    // Remove toggle classes and attributes from all menu items except the active one and its parents.
    container.find( '.dropdown-toggle.toggle-on' )
             .not( _this )
             .not( _this.parents( '.children, .sub-menu' )
                 .prev( '.dropdown-toggle' )
             )
             .removeClass( 'toggle-on' )
             .attr( 'aria-expanded', false );

    ...

} );

My attempts at pure JS code:

var container = document.querySelector( '.main-navigation' );
container.querySelectorAll( '.dropdown-toggle' ).forEach( item => {
    item.addEventListener( 'click', function( e ) {
        var _this = e.target;
        e.preventDefault();

        // Remove toggle classes and attributes from all menu items except the active one and its parents.
        container.querySelector( '.dropdown-toggle.toggle-on' );

        // How to convert the rest of the chained methods to pure JS?

        ???.classList.remove( 'toggle-on' ));
        ???.setAttribute( 'aria-expanded', false );

        ...

    } );

} );

Basically, I don't know how to convert the not() methods to pure JS. I've seen some people resort to the :not CSS selector but I don't know if it's possible in this case.

Any help would be appreciated.

leemon
  • 917
  • 4
  • 19
  • 47
  • 1
    Sometimes it's easier to remove a class from all, then add a class to one specific item. That's all I have time for. :\ – wazz Nov 29 '22 at 06:42
  • Does this solve your problem? [How to use jQuery method 'not()' in pure Javascript?](https://stackoverflow.com/questions/20465020/how-to-use-jquery-method-not-in-pure-javascript) – JulianDotExe Nov 29 '22 at 08:33

1 Answers1

0
var container = document.querySelector( '.main-navigation' );
container.querySelectorAll( '.dropdown-toggle' ).forEach( item => {
    item.addEventListener( 'click', function( e ) {
        var _this = e.target;
        e.preventDefault();

        // Remove toggle classes and attributes from all menu items except the active one.
        container.querySelectorAll( '.dropdown-toggle.toggle-on' ).forEach(el => {
            el.classList.remove('toogle-on');
            el.setAttribute( 'aria-expanded', false );
        }
        // add class, change attribute to clicked el
        e.target.classList.add('toogle-on');
        e.target.setAttribute( 'aria-expanded', true );

    });

} );
pier farrugia
  • 1,520
  • 2
  • 2
  • 9