1

so I am trying to do some events base on the scrolling of my Angular application.

I have a problem since I am trying to access a element in my HTML with the help of @ViewChild.

I can access the element inside ngAfterViewInit() but I can't access it outside of it. It always shows undefined.

Here is my component class:

export class NavBarComponent implements OnInit {

  @ViewChild('navBar')
  navBar:ElementRef;

  constructor(private renderer: Renderer2) {
  }

  ngAfterViewInit(){
    window.addEventListener('scroll', this.onScroll, true);
    console.log(this.navBar.nativeElement);
  }

  ngOnInit(): void {

  }

  onScroll(){
    console.log("I am scrolling right now.")
    console.log(this.navBar.nativeElement)
  }

  onResize(){

  }

  onTabClick(){

  }
}

When i console log inside ngAfterViewInit() i get the HTML element but when i console log inside onScroll() it is undetfined.

Why does my element disappears and gets undefined after viewinit? I am not using any ngIf or anything that removes the element.

Here is the component HTML code.

  <section class="et-hero-tabs" >
    <h1>STICKY SLIDER NAV</h1>
    <h3>Sliding content with sticky tab nav</h3>
    <div class="et-hero-tabs-container" #navBar>
      <a class="et-hero-tab" href="">ES6</a>
      <a class="et-hero-tab" href="">Flexbox</a>
      <a class="et-hero-tab" href="">React</a>
      <a class="et-hero-tab" href="">Angular</a>
      <a class="et-hero-tab" href="">Other</a>
      <span class="et-hero-tab-slider"></span>
    </div>
  </section>

Here is the console error: enter image description here

Allamo Olsson
  • 299
  • 2
  • 12
  • The problem is the way you call `this.onScroll`. To preserve `this`, you can: (1) define the callback as an arrow function: `onScroll = () => { ... }`, or (2) wrap the call inside an arrow function: `window.addEventListener('scroll', () => { this.onScroll(); }, true);`. – ConnorsFan May 28 '20 at 16:36
  • you can use also rxjs "fromEvent":https://www.learnrxjs.io/learn-rxjs/operators/creation/fromevent. `fromEvent(window,'scroll').subscribe(res=>{...})` this allow you unsubscribe, or delay or ... – Eliseo May 28 '20 at 16:50

1 Answers1

1

You could bind the meaning of this keyword in the callback function using bind() method. Try the following

ngAfterViewInit(){
  window.addEventListener('scroll', this.onScroll.bind(this), true);
  console.log(this.navBar.nativeElement);
}

Without binding, the scope of this keyword in the onScroll() callback doesn't point to scope of the class.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • I understand what happens now with this answer. But is there a reason why the variable gets undefined? In my case "navBar" ? Maybe what i am asking is: If is defined once, why is it not always defined? – Allamo Olsson May 28 '20 at 16:36
  • 1
    When you pass the callback directly, `this` keyword would point to scope of the function. And in the function there isn't any `navBar` variable. Using `bind(this)`, you could tell the callback to use `this` from the scope of `ngAfterViewInit()` function which would point to the class. – ruth May 28 '20 at 16:38
  • Oh, alright. So i am basically giving the class context to the function. But how come i can log other class variables? Sorry for my dumb questions. I understand what u meant i am just trying to understand why the only possible way to access that variable is on the scope of AfterViewInit. – Allamo Olsson May 28 '20 at 16:41
  • You wouldn't be able to access any member variables without the reference to `this`. Unless the variables are defined inside the function. – ruth May 28 '20 at 17:08