Search code examples
angularangular-material2

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


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

Image

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>

And gives me this unexpected result

Result screenshoot

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.

Google devtools console +review

Any help to solve this is gonna be useful.

Thanks


Solution

  • 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';
          }
        
        }