Material-design-lite: Close drawer on navigation link click

Created on 29 Jul 2015  Â·  31Comments  Â·  Source: google/material-design-lite

Component name: Layout / Navigation Drawer
Material Design spec URL for the component (if any): http://www.getmdl.io/components/index.html#layout-section/layout

It is not possible to close the navigation drawer after a click on a navigation link.
It would be great to create a new CSS class, which, when applied on a navigation link, would close the drawer after a click on the link.

Most helpful comment

:+1:

mine had to look a little more like this:

document.querySelector('.mdl-layout__drawer').addEventListener('click', function () {
  document.querySelector('.mdl-layout__obfuscator').classList.remove('is-visible');
  this.classList.remove('is-visible');
}, false);

All 31 comments

Usually a click on a link in the drawer causes the browser to navigate to another page which effectively “closes” the drawer.

I guess you have a different use-cae. Can you provide a codepen with your issue?

I don't have any codepen;
When the navigation is full ajax (e.g. with Angular UI router), the drawer is not closed on a navigation link click.

I’ll have to assume that’s because of Angular, not because of a bug in MDL. There’s been a lot of discussion on StackOverflow under the material-design-lite tag about making Angular and MDL work together. I suggest you try to help there.

Without the ability to reproduce the issue (on vanilla MDL, no Angular), I can’t really do anything. Closing this for now.

This is not a bug but a feature requests :)

@jeanmatthieud We don't support things like Angular ourselves. What we provide works for normal sites that aren't using front-end templating and routing so heavily. Either use StackOverflow to get support for getting what you want or build it yourself.

I think that people using MDL will also use a routing engine based on ajax requests.
It's too bad to not have this one in MDL core.

In order for MDL to remain 'lite', we need to ensure we're only landing changes that are specific to the Material Design specification or very closely related. For application-like primitives such as routing, your best bet is to use either Polymer or Angular + Angular Material.

OK thanks. I didn't like Angular Material (stability, complexity...) that's why I choose MDL + Angular for a simple web site.
If somebody needs the angular directive to close the drawer on nav link click, here it is :

angular.module('myModule')
    .directive('menuClose', function() {
        return {
            restrict: 'AC',
            link: function($scope, $element) {
                $element.bind('click', function() {
                    var drawer = angular.element(document.querySelector('.mdl-layout__drawer'));
                    if(drawer) {
                        drawer.toggleClass('is-visible');
                    }
                });
            }
        };
    });
<div class="mdl-layout__drawer">
    <span class="mdl-layout-title">My title</span>
    <nav class="mdl-navigation">
        <a class="mdl-navigation__link" menu-close ui-sref="myLink">My Link</a>
    </nav>
</div>

I have similar issue as above in that when a link with href="index.html#more" is clicked the nav drawer does not close.Please help.

@Billaboong As I stated before, we don’t support Angular out of the box. There’s been a lot of discussion on StackOverflow under the material-design-lite tag about making Angular and MDL work together. I suggest you try to get help there.

@surma Thanks for your reply.I am not working with Angular...It is just the material design lite

@Billaboong Using StackOverflow still stands since it is _support_ on using MDL and not a direct problem with what MDL provides.

http://consultabc.com/Test/android-dot-com/consultabc.html.Please look at the link and then minimise the browser to get a mobile view then click the menu button and the more link to experience the problem I have.Thank you.

@Billaboong As stated before, this is a _support_ area since nothing is technically wrong with what MDL is providing. Please use StackOverflow for helping with custom code to get things working the way you want.

@Garbee THank you sir.Let me use StackOverflow,

If you use jQuery, you can use this:

<script>
  $( document ).ready(function() {
    $('.mdl-navigation__link-drawer').click(function(){$('.mdl-layout__drawer').toggleClass('is-visible');});
  });
</script>

@jasonivers You're my hero!

:+1:

mine had to look a little more like this:

document.querySelector('.mdl-layout__drawer').addEventListener('click', function () {
  document.querySelector('.mdl-layout__obfuscator').classList.remove('is-visible');
  this.classList.remove('is-visible');
}, false);

This should be standard behaviour for the navigation drawer. The use-case of navigating to a section with an id # is applicable to a large number of possible implementations without Angular. Work-arounds shouldn't be needed.

Are there any plans on implementing it in the future?

Maybe it should be "standard" for some set of apps, but static sites which MDL 1.x is catered towards... Not so much.

A toggleDrawer method is now available in 1.1 (once it gets tagged soon) to let you call for closing it on click.

As far as future plans here, nothing to announce on that front. Layout is undergoing a _huge_ refactor in 2.x and we will see as that is being worked on how it should function.

Chiming in to support other's opinion that Drawer should close on link click. Yes MDL caters for 'old fashioned' web pages as well, but those should experience no negative effects from such a change. But for all 'modern web apps' that use ajax for navigation, this represents work that could be done just once here, now being repeated in all those projects.

The fact that the drawer is 'magic' (hamburger button appears automagically, layout obfuscator is added which closes onclick, etc) makes this more difficult. All is done automatically but for this one thing we need to hack around that.

Just look at number of people on this isue (+ stack overflow questions about it): please implement this change it will make MDL much better for novice users.

That is exactly what we are doing with 2.x. Reducing magic and putting control in developers hands. Also providing actual JS API documentation.

We simply can't do the technical part in the 1.x timeframe due to backwards compatibility concerns.

That's great to hear, thanks!

Due to recent events™, here’s an example on how to close the drawer when clicking a link inside the drawer using the toggleDrawer() method :)

Adding onclick listeners as suggested by @johnjelinek, for instance, breaks hashbang navigation. I cannot explain myself why.
That happens even when using toggleDrawer() as suggested by @surma.

It does not happen if the listener is in a timeout such as this:

function onDrawerNavClick(e) {
    setTimeout(() => {
        let d = document.querySelector('.mdl-layout');
        d.MaterialLayout.toggleDrawer();
    }, 100);
}
let drawerNav = document.querySelector('nav.mdl-navigation');
drawerNav.addEventListener('click', onDrawerNavClick, false);

@surma by far the best answer! However, I would target the js prepended class as the DOM hook... or add a data attribute (it's faster than searching for a class using querySelector). jsPerf is down so I can't send you a link :(

I also added a check when to fire the toggle method DRAWER.classList.contains('is-visible').

This is what I'm using in a Wordpress theme:

function close() {
  var d = document.querySelector('.mdl-layout');
  d.MaterialLayout.toggleDrawer();
}

document.querySelector('.mdl-layout__drawer').addEventListener('click', close);

There's a discussion on SO.

Here is the full solution:
menuclosesoln
applymenuclosesoln

@tyagiAnubhav14 look at the comment before yours, it has the proper solution.

Here's an Angular 2 TypeScript directive for use in the mdl nav drawer. (I had some trouble toggling the sidenav while using [routerLink] :neckbeard:)

_sidenav-router-link.directive.ts_

import { Directive, HostListener, Input } from '@angular/core';
import { Router } from '@angular/router';

@Directive({
  selector: '[sidenavRouterLink]'
})

export class SidenavRouterLinkDirective {

  constructor(private router: Router) {
  }

  @Input('sidenavRouterLink') url: Array<string>;

  @HostListener('click') onClick() {
    let layout: any;
    layout = document.querySelector('.mdl-layout');
    layout.MaterialLayout.toggleDrawer();
    this.router.navigate(this.url);
  }
}

Usage

...
<div class="mdl-layout__drawer">
    <span class="mdl-layout-title">Title</span>
    <nav class="mdl-navigation">
        <a class="mdl-navigation__link" [sidenavRouterLink]="['/wherever']">Wherever</a>
        <a class="mdl-navigation__link" [sidenavRouterLink]="['/somewhere']">Somewhere</a>
    </nav>
</div>
...

Where /wherever and /somewhere are both child routes of a route with a drawer layout, which might look something like

...
export const MyAwesomeRoutes : RouterConfig = [{
    path: '/',
    component: NavDrawerLayoutComponent,
    children: [
        { path: 'wherever', component: WhereverComponent },
        { path: 'somewhere', component: SomewhereComponent }
    ]
}];

There are enough solutions posted now that developers can get the idea of how to carry out the task. I am locking this conversation since the issue has been addressed and it is now possible to achieve the desired result. Any further discussion here is distracting from getting other work done in the repository.

Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

samuelcarreira picture samuelcarreira  Â·  4Comments

dryror picture dryror  Â·  5Comments

adiramardiani picture adiramardiani  Â·  4Comments

lgg picture lgg  Â·  3Comments

s-a picture s-a  Â·  5Comments