How to impliment a sidenav Navigation drawer with a (Mini variant)

George C. picture George C. · Jan 27, 2018 · Viewed 30k times · Source

Angular material 2 community I need your help how to make mini variant like google material design example in angular Material 2.

I try to implement this but I can't make this happen

enter image description here

My code so far

  <!-- ===================================================================== -->
  <!-- SIDENAV && SIDENAV CONTAINER -->
  <!-- ===================================================================== -->
  <mat-sidenav-container>

    <mat-sidenav 
      #adminNavMenu 
      mode="side" 
      opened="true"
      style="min-width:50px; background: #F3F3F3;"
      class="shadow_right" autosize>

      <!-- MENU LEFT -->
      <app-admin-menu-left></app-admin-menu-left>

    </mat-sidenav>

   <mat-sidenav-container>

app-admin-menu-left.html

<mat-nav-list style="min-width:60px;">

  <mat-list-item *ngFor="let page of Menus"> 
    <a routerLink="{{page.link}}" routerLinkActive="active" 
      [routerLinkActiveOptions]="{exact:true}" matLine>
      <mat-icon class="home_icon collapse-icon vcenter" mat-list-icon>{{page.icon}}</mat-icon>
      <span *ngIf="!showFiller">
        {{page.name}}
      </span>
    </a>
  </mat-list-item>


</mat-nav-list>

<button  mat-icon-button (click)="showFiller = !showFiller" mat-raised-button>
  <mat-icon *ngIf="!showFiller">chevron_right</mat-icon>
  <mat-icon *ngIf="showFiller">chevron_left</mat-icon> 
</button>

End gives me this unexpected result

enter image description here

After I click to view the mini bar enter image description here

As you see there is a margin 250 px on mat-sidenav-content but I can't access this element.

enter image description here

Any help to solve this is gonna be useful.

Thanx

Answer

George C. picture George C. · Apr 17, 2018

I have passed this problem with that solution.

Good luck.

Also, I have made a working example in Stackblitz

enter image description here

home.component.html

    <div>
    
      <mat-sidenav-container>
    
        <mat-sidenav #adminNavMenu mode="side" opened="true" style="min-width:60px; background: #F3F3F3;" class="shadow_right" autosize>
    
          <!-- MENU LEFT -->
          <app-admin-menu-left></app-admin-menu-left>
    
        </mat-sidenav>
    
        <!-- ================================================================= -->
        <!-- ************************* MAIN CONTAINER ************************ -->
        <!-- ================================================================= -->
        <mat-sidenav-content [@onSideNavChange]="sideNavState">
          <div class="main_container" fxLayout="column" fxLayoutGap="0px" style="height:100vh;">
    
            <!-- =============================================================== -->
            <!-- Your main content -->
            <!-- =============================================================== -->
    
          </div>
        </mat-sidenav-content>
    
      </mat-sidenav-container>
    
    
    </div>

home.component.ts


    import { Component, OnInit } from '@angular/core';
    import { MatSidenav } from '@angular/material';
    import { trigger, state, style, transition, animate } from '@angular/animations';
    
    import { MediatorService } from '@app-services/mediator/mediator.service';
    
    @Component({
      selector: 'app-admin-analytics',
      templateUrl: './admin-analytics.component.html',
      styleUrls: ['./admin-analytics.component.css'],
      animations: [
        trigger('onSideNavChange', [
          state('close',
            style({
              'margin-left': '60px'
            })
          ),
          state('open',
            style({
              'margin-left': '250px'
            })
          ),
          transition('close => open', animate('250ms ease-in')),
          transition('open => close', animate('250ms ease-in')),
        ]),
    
        trigger('onPageReady', [
          state('inactive',
            style({
              opacity: 0.4
            })
          ),
          state('active',
            style({
              opacity: 1
            })
          ),
          transition('inactive => active', animate('250ms ease-in')),
          transition('active => inactive', animate('250ms ease-in')),
        ])
      ]
    })
    export class HomeComponent implements OnInit {
    
    
      /**
       * Get the sidenav state.
       */
      sideNavState: string = this.mediator.getSideNavState;
    
 
     
      constructor(
        private mediator: MediatorService,
      ) { }
    
      ngOnInit() {
    
    
        // Subscribe on changes important.
        this.mediator.sideNavListener.subscribe( state => {
          this.sideNavState = state;
        });
    
      }
    
    
    }

mediator.service.ts


    import { Injectable } from '@angular/core';
    import { Subject } from 'rxjs/Subject';
    
    
    @Injectable()
    export class MediatorService {
    
      APP_VERSION: String = 'v8.3.1.36';
    
      // default value.
      // this variable track the value between sessions.
      private _sideState: any = 'open';
    
      /** This is the mini variant solution with animations trick. */
      sideNavListener: any = new Subject();
    
      get sideNavState() {
        return this._sideState;
      }
    
      setSidenavState(state) {
        this._sideState = state;
      }
    
    
      constructor() {
    
        this.sideNavListener.subscribe( state => {
          this.setSidenavState(state);
        });
      
    
      }
    
    
    }

menu-left.component.html


    <div class="sidenav_menu_left" 
        [@onSideNavChange]="sideNavState" 
        style="width:100%; height: 100vh;" 
        fxLayout="column" 
        [style.overflow]="overflowState">
    
        <p>Sidenav content left</p>
    
        <!-- this can toggle the sidenav -->
        <div fxFlex="100" (click)="toggleSideNav();" class="hoverble"></div>
    
    </div>

menu-left.component.ts


    import { Component, OnInit, Input } from '@angular/core';
    import { MatSidenav } from '@angular/material';
    import {trigger, state, style, transition, animate, keyframes, query, group} from '@angular/animations';
    
    
    // Mediator: the main service, later this service is gonna have more generic use.
    import { MediatorService } from '@app-services/mediator/mediator.service';
    import { delay } from 'q';
    
    
    @Component({
      selector: 'app-admin-menu-left',
      templateUrl: './admin-menu-left.component.html',
      styleUrls: ['./admin-menu-left.component.css'],
      animations: [
    
        // animate sidenave
        trigger('onSideNavChange', [
          state('close',
            style({
              width: '60px'
            })
          ),
          state('open',
            style({
              width: '250px'
            })
          ),
          transition('close => open', animate('250ms ease-in')),
          transition('open => close', animate('250ms ease-in')),
    
        ])
    
      ]
    })
    export class MenuLeftComponent implements OnInit {
    
    
      /**
       * Get the sidenav state,
       */
      sideNavState: string = this.mediator.sideNavState;
    
    
      overflowState: any = 'auto';
    
      constructor(
        private mediator: MediatorService
      ) {
    
      }
    
      ngOnInit() {
    
        this.mediator.sideNavListener.subscribe( state => {
          this.sideNavState = state;
        });
    
      }
    
      /**
       * On animation done.
       * @param x
       */
      animationEvent(x) {
        this.overflowState = 'auto';
      }
    
      /**
       * Toggle the sidenave state.
       *
       * Hides entire sidenav onclose.
       */
      setSideNavState() {
        this.mediator.toggle().then( snap => {
          console.log(snap);
        });
      }
    
    
      /**
       * Toggle, Open or close the sidenav.
       *
       * Set the sidenave state on mediator.
       */
      toggleSideNav() {
    
        switch (this.sideNavState) {
    
          case 'close':
    
            this.sideNavState = 'open';
            this.mediator.setSideNavState(this.sideNavState);
    
            setTimeout( () => {{
              this.sideNavText      = this.sideNavText === 'open' ? 'close' : 'open';
              this.sideNavIcon      = this.sideNavIcon === 'open' ? 'close' : 'open';
              this.sideNavCopyRight = this.sideNavCopyRight === 'open' ? 'close' : 'open';
            }}, 200);
          break;
    
          case 'open':
            this.sideNavText      = this.sideNavText === 'open' ? 'close' : 'open';
            this.sideNavIcon      = this.sideNavIcon === 'open' ? 'close' : 'open';
            this.sideNavCopyRight = this.sideNavCopyRight === 'open' ? 'close' : 'open';
    
            setTimeout( () => {{
              this.sideNavState = this.sideNavState === 'open' ? 'close' : 'open';
              this.mediator.setSideNavState(this.sideNavState);
            }}, 200);
          break;
    
          default:
            console.log('#6644');
            break;
        }
    
        this.overflowState = 'hidden';
      }
    
    }