6

I want to change the appearance of my navbar whenever the scroll is not at the top.

I'm using Angular Material CdkScrollable and I'm successfully retrieving the scroll Event which gives me the data about how far it is to the top.

The issue I have is that the CSS classes never changes when I scroll. I'm verifying with a console.log that the variable isScrolled is updated properly whenever I scroll down and up to the top again. So that seems to work OK. I'm using a ngClass with a ternary to validate which CSS class that should apply.

Something obvious that I'm missing?

html

<nav [ngClass]="isScrolled ? 'navbar-desktop-scrolled' : 'navbar-desktop'">
   ...
</nav>

ts

export class MainNavComponent implements AfterViewInit {
 @ViewChild(MatSidenavContainer, { static: false }) sidenavContainer: MatSidenavContainer;

 isScrolled: boolean = false;

 ngAfterViewInit() {
    this.sidenavContainer.scrollable.elementScrolled().subscribe((x) => {
      if ((<Element>x.target).scrollTop > 0) {
        this.isScrolled = true;
      } else {
        this.isScrolled = false;
      }

      console.log(this.isScrolled);
    })
  }
}
4
  • Post a complete minimal example reproducing the problem, as a stackblitz. There are too many unknowns in what you posted. Commented Jul 7, 2019 at 14:39
  • You do not scroll on the MatSidenavContainer but on the host element, so no scroll event is fired. Also there is no target property on x. The result is simply {isTrusted: true}. Commented Jul 7, 2019 at 16:31
  • You can only look if the user has scrolled, and not the scroll position. For this you can use Angular CDK scrolling. Commented Jul 7, 2019 at 16:45
  • I have created a more clear example now, stackblitz.com/edit/angular-qp6jmh. As you can see the MatSidenavContainer is indeed reacting to scroll events. I'm logging the scrollTop value to the console. Do you mean it's mandatory to use the async pipe here in order for the DOM to detect changes? Feel free to edit the StackBlitz. My goal is to have the navbar background-color to change from darkblue to lightblue as you see per the CSS-classes. Commented Jul 10, 2019 at 8:52

4 Answers 4

7

Everything works fine after I added change detection functionality.

export class MainNavComponent implements AfterViewInit {
 @ViewChild(MatSidenavContainer, { static: false }) sidenavContainer: MatSidenavContainer;

 isScrolled: boolean = false;

 constructor(private ref: ChangeDetectorRef) { }

 ngAfterViewInit() {
    this.sidenavContainer.scrollable.elementScrolled().subscribe((x) => {
      if ((<Element>x.target).scrollTop > 0) {
        this.isScrolled = true;
      } else {
        this.isScrolled = false;
      }

      this.ref.detectChanges();
    })
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

for me its still happening even with cdr
2

Your code does not work because the changes are not detected. Use an Observable in combination with the async pipe instead. It handles subscriptions automatically for you.

export class MainNavComponent implements AfterViewInit {
  @ViewChild(MatSidenavContainer, { static: false }) 
  sidenavContainer: MatSidenavContainer;
  navbarType$: Observable<string>;

  ngAfterViewInit() {
    this.navbarType$ = this.sidenavContainer.scrollable.elementScrolled().pipe(
      map(x => x.target.scrollTop > 0
        ? 'navbar-desktop-scrolled'
        : 'navbar-desktop'
      )
    )
  }
}

And in your template use

<nav [ngClass]="navbarType$ | async"></nav>

1 Comment

I tried with async pipe but I can't get it to work. Here's a StackBlitz, stackblitz.com/edit/angular-4bcnpr
0

use ngClass in the object syntax like

<nav [ngClass]="{'navbar-desktop-scrolled' :isScrolled, 'navbar-desktop': !isScrolled}">
   ...
</nav>

1 Comment

Sorry, no difference.
-1

Check out the documentation: ngClass

Object - keys are CSS classes that get added when the expression given in the value evaluates to a truthy value, otherwise they are removed.

It should look like something like this:

<some-element [ngClass]="{'navbar-desktop-scrolled': isScrolled , 'navbar-desktop' : !isScrolled  }">...</some-element>

1 Comment

The documentation you linked to also says: string - the CSS classes listed in the string (space delimited) are added.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.