Search code examples
htmlcssangularjsangular-ng-ifng-hide

Bootstrap AngularJS Hide ul if no li


Is there a way to use ng-hide or ng-if (i.e. inside the element, not the controller) to hide the #navbar-nav ul if it has no li or visible li?

Perhaps this can be extended to hide the toggle button as well since there is nothing to show.

Currently if there are no list items, then you can still toggle (slide up and down) the navbar, and it does not look nice.

Most of the other questions I saw had to do with ng-repeat

<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>
    <div class="collapse navbar-collapse">
      <ul class="nav navbar-nav" id="navbar-nav">
        <li class="active hidden-xs">
          <a href="#">Home</a>
        </li>
        <li class="hidden-xs">
          <a href="#products">Products</a>
        </li>
        <li class="hidden-xs">
          <a href="#overview">Overview</a>
        </li>
      </ul>
    </div>
    <!--/.nav-collapse -->
  </div>

JSFiddle


Solution

  • There are a few things we need to touch on here. The first is that the entire reason you use angular is to do data binding to manipulate/populate the view. With that being said you need to have something for ng-if/ng-show/ng-hide to check against. And this is where the controller comes in. The controller has to contain information so that the view can be manipulated. So in this case we will want to create a controller that has a variable to contain the menu list items:

    app.controller('navCtrl', function(){
      this.menuItems = [
        { name: 'Home', href: '' },
        { name: 'Products', href: '' },
        { name: 'Overview', href: '' }
      ];
    });
    

    Now that this is done we need to bind it to the nav:

    <div ng-controller="navCtrl as nav" class="navbar navbar-inverse navbar-fixed-top" role="navigation"> .... </div>

    Next the nav li items will need to have an ng-repeat on them so that you can populate the ul

    <ul class="nav navbar-nav">
      <li ng-repeat="navItem in nav.menuItems">
        <a ng-href="{{ navItem.href }}">{{ navItem.name }}</a>
      </li>
    </ul>
    

    Now you can start doing what you are asking. Simply add a ng-if that check if there are nav items:

    <ul class="nav navbar-nav" ng-if="nav.menuItems.length > 0"> ... </ul>
    

    You can also do this on the toggle menu:

    <button ng-if="nav.menuItems.length > 0" type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> ... </button>
    

    So now if the controllers menuItems is an empty array this.menuItems = [] the ul and the button will not be created.

    Which leads me to point #2. The only way that this makes sense is if you are populating the menu items through a service or and API call of some sort, or if you can dynamically create/delete nav items. If you are hard coding the array in the controller and not manipulating it then you know that the values will be present and there is no reason for this.

    My final point in this implementation is to remove the class="hidden-xs" from the li as per this implementation the nav items will not show up even if they are present when the viewport is xs.

    Here is a fiddle to check out the full implementation: http://jsfiddle.net/9shaakw9/2/

    Hope this helps!