Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Gabriel Ward
Gabriel Ward
20,222 Points

Removing class from unordered list using jQuery

I have a list and I'd like to remove a Advanced Search list item from it using jQuery. I can't seem to get it to work though.

Here's the list code:

<div class="menu">
        <nav id="nav-main">
            <ul>
                <li class='navMainItems'><a href="index.html">Home</a></li>
                <li class='navMainItems'><a href="publicationsSubjects.html">Publications</a></li>
                <li class='navMainItems'><a href="peoplePage.html">People</a></li>
                <li class='navMainItems'><a href="imageSubjectsPage.html">Images</a></li>
                <li class='navMainItems'><a href="maps.html">Maps</a></li>
                <li class='navMainItems'><a href="projectsList.html">Projects</a></li>
                <li class='navMainItems'><a href="audio.html">Audio</a></li>
                <li class='navMainItems'><a href="video.html">Video</a></li>
                <li class='navMainItems'><a href="collectionsList.html">Collections</a></li>
                <li class='advancedSearch'><a href="searchForm.html">Advanced Search</a></li>
                <li class='searchNav'>
                    <form class="searchbox">
                        <span class="searchbox-icon toggle">Search</span>
                    </form>
                </li>
            </ul>
        </nav>

Here's my jQuery, the code I've got to remove the Advanced Search list item is the first line, but it's not working and I've tried a range of options.

    $('#nav-main').removeClass('ul li .advancedSearch');
    $("#nav-mobile").html($("#nav-main").html());
    $("#nav-trigger span").click(function(){
        if ($("nav#nav-mobile ul").hasClass("expanded")) {
            $("nav#nav-mobile ul.expanded").removeClass("expanded").slideUp(250);
            $('#nav-mobile').addClass('searchBar');
            $(this).removeClass("open");
        } else {
            $("nav#nav-mobile ul").addClass("expanded").slideDown(250);
            $(this).addClass("open");
        }
    });
});

Any suggestions/help would be much appreciated.

2 Answers

Damien Watson
Damien Watson
27,419 Points

Hi Gabriel,

You need to target the element you want to remove the class from and then remove it, so:

$('#nav-main li.advancedSearch').removeClass('advancedSearch');

If you wanted to remove the item all together, you would target it and then remove:

$('#nav-main li.advancedSearch').remove();
Gabriel Ward
Gabriel Ward
20,222 Points

Hi Damien,

Thank you for your help. Your suggestion of

$('#nav-main li.advancedSearch').remove();

is actually what I was looking for. I believe I misunderstood the problem and only realised now with your solution. Am I right in thinking that even if you remove the class from an item it will still appear on the page? Because I actually wanted to remove the item altogether, so that the 'Advanced Search' text is actually removed. Not just the class.

Damien Watson
Damien Watson
27,419 Points

You are correct, I had a feeling you were wanting to remove the element altogether but wanted to answer the 'removeClass' question first. Glad to help. :)

Gabriel Ward
Gabriel Ward
20,222 Points

Ok great thanks. Where does .html() come into this? Is it used to only add elements and not remove them?

Damien Watson
Damien Watson
27,419 Points

'.html()' is more of an injection of html, replacing the elements content. Every element can have text or html inside it, so if you had a 'div' and wanted to put a paragraph tag in it you could inject the html for that straight into the 'div', replacing what was there.

<div id="myDiv">This is the <strong>old</strong> content</div>
$("#myDiv").html('Replaced with <strong>new</strong> html!!');
// --> <div id="myDiv">Replaced with <strong>new</strong> html!!</div>

In the instance below (from your code), it is replacing all html inside '#nav-mobile' with the html from '#nav-main'.

// jQuery
$("#nav-mobile").html($("#nav-main").html());

// Javascript  -- a bit more verbose, but it is doing this:
document.getElementById("nav-mobile").innerHTML = document.getElementById("nav-main").innerHTML;
Gabriel Ward
Gabriel Ward
20,222 Points

More specifically I want to have the 'Advanced Search' item removed only when the mobile nav is expanded. Otherwise it wants to be present. How would I do this? Currently this is my code:

$(document).ready(function(){
    $("#nav-mobile").html($("#nav-main").html());
    $("#nav-trigger span").click(function(){
        if ($("nav#nav-mobile ul").hasClass("expanded")) {
            $("nav#nav-mobile ul.expanded").removeClass("expanded").slideUp(250);
            $(this).removeClass("open");
            $('.advancedSearch').html();
        } else {
            $("nav#nav-mobile ul").addClass("expanded").slideDown(250);
            $(this).addClass("open");
            $('.advancedSearch').remove();
        }
    });
});

However when I close the mobile nav and go back to the nav main, the Advanced Search item is no longer present.

Cheers for any help.

Damien Watson
Damien Watson
27,419 Points

Ok, rather than removing it, sounds like you just want to hide it. If you remove it, you would have to add it again. Easiest way would be to create a class that maybe has 'display:none;' which gets added or removed from that element, you can use jQuery.toggleClass() for this. Something like:

.hideAdvanced    { display:none; }
$(document).ready(function(){
    $("#nav-mobile").html($("#nav-main").html());
    $("#nav-trigger span").click(function(){
        if ($("nav#nav-mobile ul").hasClass("expanded")) {
            $("nav#nav-mobile ul.expanded").removeClass("expanded").slideUp(250);
            $(this).removeClass("open");
            $('.advancedSearch').toggleClass("hideAdvanced");
        } else {
            $("nav#nav-mobile ul").addClass("expanded").slideDown(250);
            $(this).addClass("open");
            $('.advancedSearch').toggleClass("hideAdvanced");
        }
    });
});
Gabriel Ward
Gabriel Ward
20,222 Points

Hmm the toggleClass option doesn't seem to be working. Do you have any thoughts on how I can add .advancedSearch to the html if the mobile nav doesn't have the class 'expanded?' I'm guessing it's essentially, the opposite of .remove();?

Damien Watson
Damien Watson
27,419 Points

Sorry Gabriel, I think I'm confused which probably doesn't help. Do you have 2 navigation items? One which is for desktop and one for mobile, if so why not just use one and style it?

Gabriel Ward
Gabriel Ward
20,222 Points

Hi Damien,

Yes I have a main nav, which displays at 900px+ and then under 900px a menu button appears. On the click of the button the items on the main nav appear in a drop down menu. I want the advanced search to appear on the main nav at 900+ but to not appear at 900-

So it's a case of adding and removing it.

Damien Watson
Damien Watson
27,419 Points

So the easiest way would be with a media query wouldn't it? This way it is off by default (caters for mobile) and if the screen size is larger than 900px, it will appear.

.advancedSearch { display:none; }

media (min-width:900px) {
  .advancedSearch { display:inline-block; }
}
Gabriel Ward
Gabriel Ward
20,222 Points

HI Damien,

So I'd tried media queries before, and I tried your suggestion here. Your suggestion as well as my previous attempts didn't work. But your suggestion got me thinking and I came up with an answer.

#nav-mobile li.advancedSearch { 
        display: none; 
}

#nav-main li.advancedSearch { 
        display: inline-block; 
}

Also, I came up with a jQuery solution as well. And it's so simple I can't believe it took me so long to come up with.

$(document).ready(function(){
    $("#nav-mobile").html($("#nav-main").html());
    $("#nav-trigger span").click(function(){
        if ($("nav#nav-mobile ul").hasClass("expanded")) {
            $("nav#nav-mobile ul.expanded").removeClass("expanded").slideUp(250);
            $('#nav-mobile').addClass('searchBar');
            $(this).removeClass("open");
            $('.advancedSearch').show();
        } else {
            $("nav#nav-mobile ul").addClass("expanded").slideDown(250);
            $(this).addClass("open");
             $('.advancedSearch').hide();
        }
    });

Really appreciate your time and help.

Damien Watson
Damien Watson
27,419 Points

No problems, but I'm still a bit confused, it looks like you have two complete navigation elements or am I misreading it?

Probably doesn't help I'm only seeing snippets of the solution, but is the '#nav-mobile' an exact copy of '#nav-main'? I was thinking you would just manipulate the look of the main to suit mobile layout rather than duplicating.

Either way, glad you've got it working. :)

Gabriel Ward
Gabriel Ward
20,222 Points

You can see where I'm coming from with this tutorial

http://callmenick.com/_development/simple-responsive-navigation/

Basically the #nav-main is attached to the #nav-mobile, and it's in the form of a dropdown menu.