3

I'm using the offcanvas experiment code from Bootstrap 4 documentation, but it's not designed to close when you click outside the menu, which is something I would really like it to do.

I've tried several of the jquery snippets around the web, but they utilize bootstrap's .collapse and don't work when I edit them to contain the custom .offcanvas-collapse class.

<nav class="navbar fixed-top navbar-dark bg-dark">
      <button class="navbar-toggler p-0 border-0" type="button" data-toggle="offcanvas" data-target="#offcanvasNav" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
            <i data-feather="menu"></i>
          </button>
            <a class="navbar-brand" href="#">Sleight of Word</a>
            <button class="navbar-toggler p-0 border-0" type="button" data-toggle="searchBar">
              <i data-feather="search"></i>
            </button>
            <form class="form-inline my-2 my-lg-0 d-none">
              <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
              <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>

          <div class="navbar-collapse offcanvas-collapse" id="offcanvasNav">
            <ul class="navbar-nav mr-auto">
              <li class="nav-item active">
                <a class="nav-link" href="#">Dashboard <span class="sr-only">(current)</span></a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Notifications</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Profile</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Switch account</a>
              </li>
              <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Settings</a>
                <div class="dropdown-menu" aria-labelledby="dropdown01">
                  <a class="dropdown-item" href="#">Action</a>
                  <a class="dropdown-item" href="#">Another action</a>
                  <a class="dropdown-item" href="#">Something else here</a>
                </div>
              </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
              <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
              <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>
          </div>
        </nav>

.offcanvas-collapse {
    position: fixed;
    top: 56px; /* Height of navbar */
    bottom: 0;
    right: 100%;
    width: 240px;
    padding-right: 1rem;
    padding-left: 1rem;
    overflow-y: auto;
    visibility: hidden;
    background-color: purple;
    transition: visibility .2s ease-in-out, -webkit-transform .2s ease-in-out;
    transition: transform .2s ease-in-out, visibility .2s ease-in-out;
    transition: transform .2s ease-in-out, visibility .2s ease-in-out, -webkit-transform .2s ease-in-out;
  }

  .offcanvas-collapse.open {
    visibility: visible;
    -webkit-transform: translateX(100%);
    transform: translateX(100%);
  }


$(function () {
  'use strict'

  $('[data-toggle="offcanvas"]').on('click', function () {
    $('.offcanvas-collapse').toggleClass('open')
  })
})

$(document).on('click',function(){
    $('.offcanvas-collapse').offcanvas-collapse('hide');
})

I was hoping that this would make the offcanvas nav toggleable (open and close) with the menu button and make the nav close when click outside the menu, but clicking outside the nav does nothing.

Justin Bruce
  • 33
  • 1
  • 4
  • `$(document).on('click',function()` will fire no matter where you click on the DOM. You need to exclude the button that opens the nav from that selector. – APAD1 Jul 29 '19 at 17:59
  • Possible duplicate of [jQuery click anywhere in the page except on 1 div](https://stackoverflow.com/questions/12661797/jquery-click-anywhere-in-the-page-except-on-1-div) – APAD1 Jul 29 '19 at 17:59
  • @APAD1 Thank you for responding. I've updated my question since, after looking at the possible duplicate, I was still unable to solve my problem. I am not super knowledgeable, however, so it might be going over my head. – Justin Bruce Jul 29 '19 at 19:00

2 Answers2

3
$(document).on('click',function(){
  $('.offcanvas-collapse').toggleClass('open');
})

alone, will toggle the class open on all elements having the class offcanvas-collapse in your document. If the element has the class, it will be removed, otherwise it will be added.

If you combine the above with the other snippet:

$(function () {
  'use strict'

  $('[data-toggle="offcanvas"]').on('click', function () {
    $('.offcanvas-collapse').toggleClass('open')
  })
})

..., every time you click on [data-toggle="offcanvas"], both snippets are running (because you click on [data-toggle="offcanvas"] but you also click on document (because click event bubbles all the way up to document, unless prevented). Therefore the class offcanvas-collapse gets toggled twice, so it will look like it's not working.

That's clearly not what you're after.

You probably want to:

  • toggle the class open on .offcanvas-collapse elements when [data-toggle="offcanvas"] is clicked without allowing that click event to propagate to document.
  • remove (not toggle) the class open from .offcanvas-collapse elements when a click is performed anywhere in the document. If you use toggle, a click in document when offcanvas is closed will open it, which is probably not what you want.

That being said, here's the practical way to do it:

$(function () {
  'use strict'

  $(document)
    .on('click', '[data-toggle="offcanvas"]', function(e) {
      $('.offcanvas-collapse').toggleClass('open'); // toggle `.open`
      e.stopPropagation(); // and stop propagation
    })
    .on('click', function() {
      $('.offcanvas-collapse').removeClass('open'); // remove `.open`
    });
})

Edit: as per the comment request, to only close the off-canvas when clicking outside of the navbar, replace the second .on() with this one:

.on('click', function(e) {
   if (!$(e.target).closest('nav.fixed-top').is('nav')) {
     $('.offcanvas-collapse').removeClass('open'); // remove `.open`
   }
 });

It check is the target clicked is inside a <nav> with class fixed-top.

tao
  • 82,996
  • 16
  • 114
  • 150
  • 1
    Yes, that worked. Thank you for the snippet and especially for the explanation! – Justin Bruce Jul 29 '19 at 19:16
  • Hi, sorry to bother you again. I realized today that when I click on anything in the nav, including the search form, the nav collapses and goes away. Is there a way to make it collapse only if you click on something other than the nav? Thanks. – Justin Bruce Jul 30 '19 at 15:45
  • @Justin, I added to the answer on how to achieve it. – tao Jul 30 '19 at 17:59
  • 1
    Your edit worked. Thank you. This is the jsfiddle in case anyone wants it: https://jsfiddle.net/jedimasterbruce/tfyhw96a/8/ – Justin Bruce Jul 30 '19 at 18:05
2

In case anyone stumbles here after all this time, you just have to

$('#your_offcanvas_id').offcanvas('hide');

and to open offcanvas('show')