3

In angular, I use scrollDispatcher(checking scrolling) change variable flag at html DOM, but the DOM(ngif) not work, there is my testing code:

// html
<div *ngIf="scrollState">
  scrolling!
</div>

// TS
import { ScrollDispatcher } from '@angular/cdk/scrolling';
...
scrollState = false;
...
constructor( private scrollDispatcher: ScrollDispatcher){
    let self = this;
    this.scrollDispatcher.scrolled().subscribe( function () {
      self.scrollState = true;
      console.log('now scrolling!', self.scrollState ); 
      //checking scrollState, it's true
    });
}

When I scrolling, the DOM is not show, but I checking self.scrollState is really true, why? I can't understand, please help me, thank you.

Specific example

//html
<div class="sectionStickyTitle" *ngIf="sectionStickyTitleState">
  <h2>Test new title</h2>
</div>

<h1 class="section-h1" #sectionh1>I'm check top target</h1>

//TS
import { ScrollDispatcher } from '@angular/cdk/scrolling';
...
@ViewChild('sectionh1') sectionh1: ElementRef;
sectionStickyTitleState = false;
sectionhOffsetTop: number;
...
constructor(private scrollDispatcher: ScrollDispatcher, ...){
}

ngOnInit(){
 ...
 this.scrollDispatcher.scrolled().subscribe(() => this.setSectionStickyTitle());
}

...
setSectionStickyTitle() {
  this.sectionhOffsetTop = this.sectionh1.nativeElement.getBoundingClientRect().top;

  this.sectionStickyTitleState = (this.sectionhOffsetTop <= 21) ? true : false;

  console.log('sectionStickyTitleState --> ', this.sectionStickyTitleState);
  console.log('sectionhOffsetTop --> ', this.sectionhOffsetTop);
}

I re-edited the problem, the purpose is the same, the flag can not be recognized by html, when the height of #sectionh1 is less than 21, flag must be true, it is also true, but *ngIf="sectionStickyTitleState"(flag) always unable to respond.

This really makes me hard to understand because console.log always means flag is true.

Community
  • 1
  • 1
Pork Jackson
  • 339
  • 1
  • 15
  • can you give some more detail about what exactly you want to do? do you want to capture scroll events on a certain element or any element in DOM or just document/window? also what are you going to do when you handle the event? – ysf Jul 05 '19 at 11:12
  • @ysf Hi, I re-edited my question, the specific example has more details. thank you. – Pork Jackson Jul 05 '19 at 12:07

2 Answers2

6

according to docs

in order to avoid hitting change detection for every scroll event, all of the events emitted from this stream will be run outside the Angular zone. If you need to update any data bindings as a result of a scroll event, you have to run the callback using NgZone.run.

so, do as follows;

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

ngOnInit() {
  this.scrollDispatcher.scrolled().subscribe(() => {
    this.zone.run(() => {
      this.setSectionStickyTitle();
    });
  });
}

i also created a demo here https://stackblitz.com/edit/angular-msn4ma

in demo above when you scroll body or div1 template bindings update properly. but if you scroll div2 template bindings doesn't update even though it prints the console.

hope it helps.

ysf
  • 4,634
  • 3
  • 27
  • 29
1

There are few changes I would suggest in your code, use this instead of let and use an arrow function

constructor( private scrollDispatcher: ScrollDispatcher){
    this.scrollDispatcher.scrolled().subscribe() => {
      this.scrollState = true;
      console.log('now scrolling!', this.scrollState ); 
    });
}
Sajeetharan
  • 216,225
  • 63
  • 350
  • 396
  • thank's, I change an arrow, but ngif still not working :( – Pork Jackson Jul 05 '19 at 10:25
  • try {{scrollState}} on html and see – Sajeetharan Jul 05 '19 at 10:36
  • In fact, it is not the original purpose to react when scrolling. I originally had the offsetTop to judge other DOMs, but it also didn't work, so I just wanted to confirm if there are other possibilities. It's like " if(offset <= number), flag = true/false ...", so I can't just rely on scrollstate :( – Pork Jackson Jul 05 '19 at 10:52