1

Anyone know why in this plunker the Material Design Lite sidenav (or drawer as they call it) won't display when used as a component?

It works fine when it's not used as a component like in this plunker

I'm using the following but maybe in the wrong area????

componentHandler.upgradeAllRegistered();
Post Impatica
  • 14,999
  • 9
  • 67
  • 78

3 Answers3

1

I'm struggling with this as well. I have the the component mostly working, but it does not dismiss the drawer when I click the content.

I found this helpful: https://stackoverflow.com/a/35451821/1341825

Try adding the mdl attribute to your root node. Like:

<div mdl class="mdl-layout mdl-js-layout mdl-layout--fixed-header">

Community
  • 1
  • 1
theUtherSide
  • 3,338
  • 4
  • 36
  • 35
  • I also use this in my applciation. – Edmond Wang May 24 '16 at 05:29
  • I looked at the link you provided and also tried the custom directive they talked about using `componentHandler.upgradeElement(el.nativeElement);` but it still didn't work. – Post Impatica May 24 '16 at 13:57
  • 1
    By the way, i think i had the same issue you are describing where the drawer wouldn't close before i fixed the CSS issue. You have to use `encapsulation: ViewEncapsulation.None` in each of your components, otherwise the css rules are blocked out by default. – Post Impatica May 24 '16 at 14:07
  • 1
    Like i said though, i can get the drawer to work (and I provided an example) if i leave the drawer in the original html of the entire page, but if i break it off into it's own component, that's when it breaks. – Post Impatica May 24 '16 at 14:09
  • Thanks for the tip about `encapsulation`. It didn't solve the issue with the drawer....will keep trying and report back here. – theUtherSide May 24 '16 at 22:05
  • Turns out i had mis-matched versions in my references to the MDL CSS and JS. Doh. All working now. Setting `ViewEncapsulation.None` made my CSS work at the component level too. I'm using the directive as-described in the link in my answer. In your non-working example, I think the drawer needs to be included in the same template as the header. I was not able to break it out into a partial, even when I nest the partial within `
    `
    – theUtherSide May 24 '16 at 22:44
1

I don't think this can be done using Material Design Lite, at least not now. I ended up using Angular Material 2 and was able to separate the sidenav into it's own component. View this plunker for an example.

Following is the code in case the link doesn't work.

app.component.html

<my-sidenav></my-sidenav>

app.component.ts

import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
import {SidenavComponent} from 'sidenav.component.ts';
import {GlueService} from 'glue.service.ts';

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html',
  directives: [SidenavComponent],
  providers: [GlueService]
})
export class AppComponent {
}

bootstrap(AppComponent);

Since the sidenav is an outside container to everything else it has to be loaded first:

sidenav.component.html

<md-sidenav-layout>
<md-sidenav #start [opened]="opened" id="left_sidenav" layout-padding>
<h2>Sidenav</h2>
<button md-raised-button class="md-raised md-primary" (click)="start.close()">Close</button>
</md-sidenav>
<md-content>
<my-content></my-content>
</md-content>
</md-sidenav-layout>

sidenav.component.ts

import {Component, ViewChild} from '@angular/core';
import {MdButton} from '@angular2-material/button';
import {MD_SIDENAV_DIRECTIVES, MdSidenav} from '@angular2-material/sidenav';
import {ContentComponent} from 'content.component.ts';
import {GlueService} from 'glue.service.ts';

@Component({
  selector: 'my-sidenav',
  templateUrl: 'sidenav.component.html',
  directives: [MdButton, MD_SIDENAV_DIRECTIVES, ContentComponent],
  providers: []
})
export class SidenavComponent{
opened: false;
@ViewChild('start') sidenavComponent: MdSidenav;
constructor(private glueService: GlueService) {

glueService.toggleConfirmed$.subscribe(
  toggle => {
    this.toggleLeftNav();
  });
}
toggleLeftNav(){

 (<MdSidenav>this.sidenavComponent).open();

}

}

The content component contains the header and the content. You could easily split this up into 2 components.

content.component.html

<md-toolbar color="primary">
<button md-raised-button style="color:black;margin:10px" (click)="openLeftNav()">Open Sidenav</button>
Angular Material 2 App
</md-toolbar>
<h2>Content</h2>

content.component.ts

import {Component,  OnDestroy} from '@angular/core';
import {MdToolbar} from '@angular2-material/toolbar';
import {MdButton} from '@angular2-material/button';
import { GlueService } from 'glue.service.ts';

@Component({
  selector: 'my-content',
  templateUrl: 'content.component.html',
  directives: [MdToolbar, MdButton]
})
export class ContentComponent implements OnDestroy{
   constructor(private glueService: GlueService) { }

   openLeftNav(){
     this.glueService.confirmToggle(true);
   }

}

I created a service (no idea what to call it) that allows the different components to talk to each other. I called it glue.service.ts. I also don't know if this is the BEST way for one component to talk to another although this method was mentioned in Angular 2's cookbook.

glue.service.ts

import { Injectable } from '@angular/core'
import { Subject }    from 'rxjs/Subject';
@Injectable()
export class GlueService {
  private toggleAnnouncedSource = new Subject<boolean>();
  private toggleConfirmedSource = new Subject<boolean>();
  // Observable string streams
  toggleAnnounced$ = this.toggleAnnouncedSource.asObservable();
  toggleConfirmed$ = this.toggleConfirmedSource.asObservable();
  // Service message commands
  announceToggle(toggle: boolean) {
    this.toggleAnnouncedSource.next(toggle)
  }
  confirmToggle(toggle: boolean) {
    this.toggleConfirmedSource.next(toggle);
  }
}
Post Impatica
  • 14,999
  • 9
  • 67
  • 78
  • 1
    Did you had a look to my answer? I would not say this is not possible with **Material Design Lite**. But Angular Material 2 will probably be easier to use with Angular. – hr_117 May 27 '16 at 09:37
  • I agree, Material 2 is easier, when you start doing things like *ngIf you'll wish you were using MD2 instead of MDL. – Post Impatica May 27 '16 at 14:13
1

The basic problem in your MDL drawer as Angular component is, that mdl-layout__drawer needs to be a direct child of mt mdl-js-layout.
But in your "generated" html the <my-sidenav>is still the parent of mdl-layout__drawer

  <div data-upgraded=",MaterialLayout" class="mdl-layout mdl-js-layout mdl-layout--fixed-header is-small-screen is-upgraded">
    <div class="android-header mdl-layout__header mdl-layout__header--waterfall">..</div>
     <my-sidenav>   
       <div class="android-drawer mdl-layout__drawer">
        <nav class="mdl-navigation">
          <a href="" class="mdl-navigation__link">Nav 1</a>
        </nav>
       </div>
      </my-sidenav>
      <div mdl="" class="android-content mdl-layout__content">
        <h2>Content stuff here</h2>...
      </div>
  </div

To avoid that you may change your component to Attribute directive.

@Component({
    selector: '[my-sidenav]',
    ...

And use it like this:

<div my-sidenav class="android-drawer mdl-layout__drawer"></div> 

Have a look to the changed plunker

hr_117
  • 9,589
  • 1
  • 18
  • 23