Twitter Bootstrap Navbar with AngularJS - Collapse Not Functioning
Asked Answered
F

8

71

I am using Angular and Twitter Bootstrap navbar and trying to get the collapse functionality to work.

Partial: program.html

<div class="navbar navbar-inverse navbar-static-top" ng-include="'partials/navbar.html'" ng-controller="NavbarCtrl"></div>

Partial: navbar.html

<div class="navbar-inner">
    <div class="container">
        <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </a>
        <a class="brand" href="#">Short Course</a>
        <div class="nav-collapse collapse">
            <ul class="nav">
                <li><a href="#"><i class="icon-home icon-white"></i> Home</a></li>
                <li class="dropdown ng-class: settingsActive;">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Intro <b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li><a onclick='$("#myModal").modal("show");'>User Info</a></li>
                        <li><a href="#/setup">Settings</a></li>
                        <li><a href="#/get-started">Getting started</a></li>
                    </ul>
                </li>
                <li class="dropdown ng-class: programActive;" ng-controller="ProgramCtrl">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Lessons <b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li ng-repeat='o in lessonTypes'>
                            <a href="#/program/{{o.value}}">{{o.title}}</a>
                        </li>
                        <li class="divider"></li>
                        <li><a href="#/freeform">Free Form</a></li>
                    </ul>
                </li>
                <li class="dropdown ng-class: reportsActive;">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Grades <b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Simple Report</a></li>
                        <li><a href="#">Comprehensive Report</a></li>
                        <li class="divider"></li>
                        <li><a href="#">Current Grade Report</a></li>
                        <li><a href="#">Final Grade Report</a></li>
                    </ul>
                </li>
            </ul>
            <ul class="nav pull-right">
                <li><a href="#/class"><i class="icon-upload icon-white"></i> Upload/Save</a></li>
                <li><a href="#/class"><i class="icon-off icon-white"></i> Save/Logout</a></li>
            </ul>
        </div><!-- /.nav-collapse -->
    </div>
</div><!-- /navbar-inner -->

The navbar displays perfectly. The dropdowns work great. The Angular functions load the data and mark the specific items as active and populate the models perfectly. The only thing that doesn't work is the responsive collapse feature. When I resize the screen, the menu items disappear and the icon for the menu appears, but clicking on it does not work. I am stuck on this and I know it has to be a simple fix, but I just can't figure it out. Any help would be appreciated!

Felodese answered 7/2, 2013 at 1:21 Comment(4)
did you include Collapse.js from bootstrap i think it should be missing if still it does not work could you share jsfiddleConstrictive
Word. It is included, and I used the plugin with an accordion on a different partial.Felodese
could you share fiddle for itConstrictive
Figured it out, answered below.Felodese
F
7

This was a tricky one. The docs showed one way, and it functions great. I copied the docs example (http://twitter.github.com/bootstrap/components.html#navbar) and tried using it. I then went to the examples page and tried the layout listed here: http://twitter.github.com/bootstrap/examples/fluid.html

The one and only difference was a <button> instead of <a>

<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">

Instead of

<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">

I don't know why, but changing that made it function great.

EDIT

Arbiter pointed out that the <a /> was missing the href='#' attribute. Adding that attribute would also solve the problem.

Felodese answered 11/2, 2013 at 15:58 Comment(3)
I think it's because your link was missing href="#" - so the default link behavior wasn't removed.Wide
That is 100% correct now that I am looking at it. I will edit the answer and put that in. Thanks! If only you were around the day I asked the question I could have avoided a major headache.Felodese
I only appear when I'm no longer required.Wide
T
103

For those interested - Here is another way of implementing this without Bootstrap's javascript.

Import Angular's UI-Bootstrap.

HTML:

<div class="navbar navbar-inverse" ng-controller="NavBarCtrl">
<div class="navbar-inner">
    <div class="container">
        <button class="btn btn-navbar" ng-click="isCollapsed = !isCollapsed"> 
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
        </button> <a class="brand" href="#">Short Course</a>
        <div class="nav-collapse" uib-collapse="isCollapsed">
            <ul class="nav">
                <li><a href="#"><i class="icon-home icon-white"></i> Home</a>
                </li>
                <li><a href="#">Lessons</a>
                </li>
                <li><a href="#">Grades</a>
                </li>
            </ul>
            <ul class="nav pull-right">
                <li><a href="#/class"><i class="icon-upload icon-white"></i> Upload/Save</a>
                </li>
                <li><a href="#/class"><i class="icon-off icon-white"></i> Save/Logout</a>
                </li>
            </ul>
        </div>
        <!-- /.nav-collapse -->
    </div>
</div>
<!-- /navbar-inner -->
</div>

JS:

var myApp = angular.module('myApp', ['ui.bootstrap']);

function NavBarCtrl($scope) {
    $scope.isCollapsed = true;
}

And the fiddle - http://jsfiddle.net/KY5Mf/

Tagmeme answered 16/7, 2013 at 9:16 Comment(4)
Updated for Bootstrap 3.x - jsfiddle.net/z2hLy - worth noting that if you don't need the menu dropdowns, you only need to import ['ui.bootstrap.collapse'].Tagmeme
bs-js-navbar-collapse! The missing piece! Where's that documented?Appliance
FYI you need to use the uib-collapse directive instead of collapse nowSchnapp
Broken fiddle. Should be fixed.Sferics
C
82

I wanted to get it to work with pure AngularJS and no further JavaScript library and it turned out to be quite simple. There are only two changes needed starting with the example here (bootstrap v3):

Instead of

<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">

I used:

<button type="button" class="navbar-toggle" ng-init="isCollapsed = true" ng-click="isCollapsed = !isCollapsed">

and instead of

<div class="collapse navbar-collapse">

I used:

<div class="navbar-collapse" ng-class="{collapse: isCollapsed}">

Dropdowns

Also, if you have any dropdown menus in your navbar, the same applies to them, except the css class is not 'collapse', but 'open':

<li class="dropdown" ng-class="{ open : dd1 }" ng-init="dd1 = false" ng-click="dd1 = !dd1">

Note that multiple dropdowns will all need their own state variable on the angular root scope (if you are not using a controller). Therefore I named the first dropdown 'dd1' here, they need to be unique, otherwise multiple dropdown will open/close at the same time. (which is pretty funny, but rarely usable).

Couple answered 28/5, 2014 at 17:51 Comment(10)
This helped me out greatly, please add to your answer that this also works for the dropdowns in the NavBar. [li class="dropdown" ng-class="{ open : isDropDownCollapsed}" ng-init="isDropDownCollapsed = false" ng-click="isDropDownCollapsed = !isDropDownCollapsed"]Eggert
@GerbenRampaart: Please feel free to edit my answer.Couple
it helped me a lot. Thank you! If you have to dropdowns (dd1 and dd2) and you want to close dd1 when opening dd2 you can do this by ng-click="dd2 = !dd2; dd1 = false"Vookles
This worked for me as well. I did not need to add anything to the controllers.Headword
Thanks a ton, this was perfect! Not sure why this isn't the accepted answer.Ariminum
@shadowhand: It's probably not the accepted answer because I posted this answer more than a year after the accepted answer ;-).Couple
This worked great, but my menu wasn't automatically collapsing when a link was clicked. So I just moved the ng-click handler to a parent <div> that contained both the button and the menu items so that both clicking on the hamburger button or clicking on a link would collapse the menu.Granuloma
I am using this, but mine are not collapsing after selecting a link.Headword
@Kode: Plz create a plunkr/jsFiddle/... so we can have a look.Couple
@Couple Thanks, your answer is still relevant for Angular2. thanks, toggle of class is needed to make it work.Hound
F
7

This was a tricky one. The docs showed one way, and it functions great. I copied the docs example (http://twitter.github.com/bootstrap/components.html#navbar) and tried using it. I then went to the examples page and tried the layout listed here: http://twitter.github.com/bootstrap/examples/fluid.html

The one and only difference was a <button> instead of <a>

<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">

Instead of

<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">

I don't know why, but changing that made it function great.

EDIT

Arbiter pointed out that the <a /> was missing the href='#' attribute. Adding that attribute would also solve the problem.

Felodese answered 11/2, 2013 at 15:58 Comment(3)
I think it's because your link was missing href="#" - so the default link behavior wasn't removed.Wide
That is 100% correct now that I am looking at it. I will edit the answer and put that in. Thanks! If only you were around the day I asked the question I could have avoided a major headache.Felodese
I only appear when I'm no longer required.Wide
Z
7

No need to engage a controller. Just use ng-init instead to initialize the isCollapsed flag when template is initially compiled.

<div class="navbar navbar-inverse" ng-controller="NavBarCtrl">
<div class="navbar-inner">
    <div class="container">
        <button class="btn btn-navbar" ng-init="isCollapsed = true" ng-click="isCollapsed = !isCollapsed"> 
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
        </button> <a class="brand" href="#">Short Course</a>
        <div class="nav-collapse" collapse="isCollapsed">
            <ul class="nav">
                <li><a href="#"><i class="icon-home icon-white"></i> Home</a>
                </li>
                <li><a href="#">Lessons</a>
                </li>
                <li><a href="#">Grades</a>
                </li>
            </ul>
            <ul class="nav pull-right">
                <li><a href="#/class"><i class="icon-upload icon-white"></i> Upload/Save</a>
                </li>
                <li><a href="#/class"><i class="icon-off icon-white"></i> Save/Logout</a>
                </li>
            </ul>
        </div>
        <!-- /.nav-collapse -->
    </div>
</div>
<!-- /navbar-inner -->
</div>
Zachery answered 18/3, 2014 at 0:29 Comment(0)
H
7

If you are looking for Angular2. Then blow is the changes required.

<button type="button" class="navbar-toggle collapsed" (click)="toggleCollapse()"
        aria-expanded="false">

and menu should look like this.

<div class="navbar-collapse" id="bs-navbar-collapse" [class.collapse]="isCollapsed">
      <ul class="nav navbar-nav">
        <li>
          <a href="">
            Dashboard

Your controller should be be something like this.

import { Component} from '@angular/core';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent {
  isCollapsed: boolean = true;

  toggleCollapse(): void {
    this.isCollapsed = !this.isCollapsed;
  }

}

See, this is relatively easy in angular2. thanks to @yankee for the answer.

Hound answered 2/10, 2016 at 12:9 Comment(0)
B
4

Here is a working implementation using the ui.bootstrap.collapse module. https://jsfiddle.net/7z8hLuyu/

HTML

<div ng-app="app">
<nav class="navbar navbar-default">
  <div class="container-fluid" ng-controller="NavigationCtrl as vm">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" ng-click="vm.toggleCollapse()">
        <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>

    <!-- Collect the nav links, forms, and other content for toggling -->
<div class="navbar-collapse" style="overflow:hidden!important;" uib-collapse="vm.    isCollapsed">
      <ul class="nav navbar-nav">
    <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></    li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link 2</a></li>
        <li><a href="#">Link 3</a></li>
        <li><a href="#">Link 4</a></li>     
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
</div>

Controller (using controllerAs syntax):

(function(){
    'use strict';

  angular
    .module('app', ['ngAnimate','ui.bootstrap.collapse'])
    .controller('NavigationCtrl', NavigationCtrl);

  NavigationCtrl.$inject = [];

  function NavigationCtrl() {
    var vm = this;
    vm.isCollapsed = true;
    vm.toggleCollapse = toggleCollapse;

    function toggleCollapse() {
        vm.isCollapsed = !vm.isCollapsed;
    }
  }

})();

Note: for animation to work in ui.bootstrap modules, you must include ngAnimate.

Bleb answered 15/2, 2016 at 20:47 Comment(0)
V
0

I feel that this will be simple JS fix:

//for close, opened dropdown.
$(".nav a").click(function () {
    if ($(".navbar-collapse").hasClass("in")) {
        $('[data-toggle="collapse"]').click();
    }
});

If this code is not working correctly then see that it's binding correctly, so place it in controller that loads page.

Vireo answered 6/12, 2014 at 7:2 Comment(0)
I
0

Just adding jquery.min.js and bootstrap.min.js to the index.html file solved this problem.

For collapsable navigation we need to include jquery.min.js and bootstrap.min.js

Ingest answered 1/12, 2015 at 4:1 Comment(1)
This is just wrong. It likely works, but this question is for Angular/Bootstrap not jQuery/Bootstrap, so your kinda steering the OP in the wrong direction. No need to introduce a dependency on jQuery for this. See noduck's and yankee's answers.Leander

© 2022 - 2024 — McMap. All rights reserved.