7

I used the example provided here to set up a responsive navbar

https://theinfogrid.com/tech/developers/angular/responsive-navbar-angular-flex-layout/

and my code looks pretty similar

<div style="height: 85vh;">

  <mat-toolbar color="primary" mat-scroll-shrink>
    <span>{{title}}</span>
    <span class="example-spacer"></span>
    <div fxShow="true" fxHide.lt-md="true">
      <!-- The following menu items will be hidden on both SM and XS screen sizes -->
      <a href="#" mat-button>Home</a>
      <a href="#" mat-button>About</a>
      <a href="#" mat-button>Services</a>
      <a href="#" mat-button>Portfolio</a>
      <a href="#" mat-button>Start</a>
      <a href="#" mat-button>FAQ</a>
      <a href="#" mat-button>Blog</a>
      <a href="#" mat-button>Contact</a>
    </div>

    <div fxShow="true" fxHide.gt-sm="true">
      <a href="#" (click)="sidenav.open()">Show Side Menu</a>
    </div>
  </mat-toolbar>

  <mat-sidenav-container fxFlexFill class="example-container">
    <mat-sidenav #sidenav fxLayout="column">
      <div fxLayout="column">
        <a (click)="sidenav.close()" href="#" mat-button>Close</a>
        <a href="#" mat-button>Home</a>
        <a href="#" mat-button>About</a>
        <a href="#" mat-button>Services</a>
        <a href="#" mat-button>Portfolio</a>
        <a href="#" mat-button>Start</a>
        <a href="#" mat-button>FAQ</a>
        <a href="#" mat-button>Blog</a>
        <a href="#" mat-button>Contact</a>
      </div>
    </mat-sidenav>
    <mat-sidenav-content fxFlexFill>

      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
      <p>Demoing some content to make this thing scroll</p>
    </mat-sidenav-content>
  </mat-sidenav-container>
</div>

What I would like to have happen is have the mat-toolbar shrink as I scroll down, which is common in a lot of sites, such as this one:

https://www.havealook.com.au/

I won't post the rest of the angular 5 code, just follow the example to re-create - its pretty quick.

I've looked at the materials website here

https://material.angular.io/components/toolbar/overview

but there's not much explanation on how to add to it, and I'm pretty new to this stuff. Does anyone know how I might customise this to make the toolbar shrink, based on scrolling?

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
Michael Coxon
  • 3,337
  • 8
  • 46
  • 68
  • have you got any progress on solving this problem – Mehavel Feb 01 '18 at 03:51
  • None, actually. I have been working on other problems. The problem is, I'm not sure how to detach the toolbar in the layout without messing up the mat-sidenav-content, and also detecting the right point in the scroll to trigger the compaction is hard too – Michael Coxon Feb 01 '18 at 05:30

1 Answers1

13

Update Nov 2018

The ScrollDispatchModule was deprecated with Angular CDK v7. Use the ScrollingModule instead.


I've created a Stackblitz with a toolbar that shrinks when scrolling down.

Main Steps

Use the CdkScrollDispatcher service to react to scroll events

  1. Import the ScrollDispatchModule in your module.
import {ScrollDispatchModule} from '@angular/cdk/scrolling';
  1. Mark the containers of which the scroll events are relevant with the directive cdkScrollable, here it is mat-sidenav-content.
 <mat-sidenav-content fxFlexFill cdkScrollable>
  1. React to scroll events in the ngOnInit of your component, get the scrollTop position and set a flag if it is larger than a certain threshold:
private readonly SHRINK_TOP_SCROLL_POSITION = 50;
shrinkToolbar = false;

constructor(private scrollDispatcher: ScrollDispatcher,
            private ngZone: NgZone) { }

ngOnInit() {
  this.scrollDispatcher.scrolled()
    .pipe(
      map((event: CdkScrollable) => event.getElementRef().nativeElement.scrollTop)
    )
    .subscribe(scrollTop => this.ngZone.run(() => this.shrinkToolbar = scrollTop > this.SHRINK_TOP_SCROLL_POSITION ? true : false));
}

You need to run this with ngZone because scrolled() events of the ScrollDispatcher are run outside of Angular by default. Without it, the ChangeDetection won't run and your templates won't be updated.

Change the toolbar layout on scroll

  1. Add a shrink css class, when the container is scrolled down
<mat-toolbar color="primary" [ngClass]="{'shrink-toolbar': shrinkToolbar}">
  1. Define the css class for the shrinked layout.
.shrink-toolbar {
  height: 32px;
}

Find more information about the scroll service in the official docs.

Community
  • 1
  • 1
Kim Kern
  • 54,283
  • 17
  • 197
  • 195
  • dude! love your work! that was perfect. The official docs could do with your help. Thank you so much. – Michael Coxon Feb 03 '18 at 21:14
  • @KimKern Thanks for your answer as well! Unfortunately your Stackblitz link is pointing to a different example. – stevo May 23 '18 at 19:52
  • @stevo I have recreated the stackblitz. – Kim Kern Aug 01 '18 at 23:04
  • @KimKern have you maybe also a solution that feels like this: https://osvaldas.info/examples/auto-hide-sticky-header/?lazy-plus ? I also opend a feature request here: https://github.com/angular/components/issues/16659 But i am sure they will need some months, maybe years to implement it =/ – Budi Aug 01 '19 at 11:44
  • @Budi You just have to take into account the scrolling direction (e.g. `oldValue - newValue > 0`). Otherwise it's pretty much the same as in my post. – Kim Kern Aug 01 '19 at 12:06
  • can you make maybe an example? i think we need to place behind the out sliding element a block element like a empty div that simulates the height of the outscroll value. that the content area grow correctly. i was not able to do this in last days. – Budi Aug 01 '19 at 13:32