1
votes

I'm trying to implement something like the following into an Angular project: https://codepen.io/vincentorback/pen/NGXjda

The code compiles just fine in VS code, but when I try and preview in the browser, I get the following two errors:

  1. Uncaught (in promise): TypeError undefined is not an object (evaluating 'this.context.addEventListener')
  2. TypeError undefined is not an object (evaluating 'this.getScrollPos')

Stackblitz: https://stackblitz.com/edit/ionic-rv4ju7

home.page.ts

export class HomePage implements OnInit {

  context = document.getElementsByClassName('loop')[0];
  startElement = document.getElementsByClassName('is-start')[0];
  clones = document.getElementsByClassName('is-clone');
  disableScroll = false;
  scrollWidth;
  scrollPos;
  clonesWidth;
  i;

  constructor() { 
    window.requestAnimationFrame(this.reCalc);
    this.context.addEventListener('scroll', function () {
      window.requestAnimationFrame(this.scrollUpdate);
    }, false);
    window.addEventListener('resize', function () {
      window.requestAnimationFrame(this.reCalc);
    }, false);
  }

getScrollPos() {
    return (this.context.pageXOffset || this.context.scrollLeft)  - (this.context.clientLeft || 0);
  }
  setScrollPos(pos) {
    this.context.scrollLeft = pos;
  }
  getClonesWidth() {
    this.clonesWidth = 0;
    this.i = 0;

    for (this.i; this.i < this.clones.length; this.i += 1) {
      this.clonesWidth = this.clonesWidth + this.clones[this.i].clientWidth;
    }
    return this.clonesWidth;
  }
  reCalc() {
    this.scrollPos = this.getScrollPos();
    this.scrollWidth = this.context.scrollWidth;
    this.clonesWidth = this.getClonesWidth();

    if (this.scrollPos <= 0) {
      this.setScrollPos(1);
    }
  }
  scrollUpdate() {
    if (this.disableScroll === false) {
      this.scrollPos = this.getScrollPos();

      if (this.clonesWidth + this.scrollPos >= this.scrollWidth) {
        // Scroll to the left when you’ve reached the far right
        this.setScrollPos(1); // Scroll 1 pixel to allow scrolling backwards.
        this.disableScroll = true;
      } else if (this.scrollPos <= 0) {
        // Scroll to the right when you reach the far left.
        this.setScrollPos(this.scrollWidth - this.clonesWidth);
        this.disableScroll = true;
      }

      if (this.disableScroll) {
        // Disable scroll-jumping for a short time to avoid flickering.
        window.setTimeout(function () {
          this.disableScroll = false;
        }, 40);
      }
    }
  }

}

1
Try to move the code from the contructor to ngOnInit. Do the same for the DOM quering code ` document.getElementsByClassName('loop')[0];` Your compoent is not yet rendered, you can't query it. It wil best if you add a stackblitz link, It will be easier to assist youMorlo Mbakop
can you please provide the html alsoFaizal Hussain
I've moved those pieces to the ngOnInit but I'm getting the same error. Please see stackblitz: stackblitz.com/edit/ionic-rv4ju7Carrie M.

1 Answers

0
votes

You need to move your code from the constructor to AfterViewInit, where DOM elements are available. As a further recommendation, I would recommend that keep what you can out of the constructor. Constructor is mainly used for initializing variables, not doing any logic.

Furthermore, you have issues with this, this doesn't point to what you think it does. Take a read: How to access the correct `this` inside a callback? Very useful reading! So I would recommend to use arrow functions instead of function to keep the context of this.

So change things like:

this.context.addEventListener('scroll', function () {

to:

this.context.addEventListener('scroll', () => {

Here's a fork of your StackBlitz

PS: where you can, make use of Angular tools instead of accessing the DOM like .getElementById. Just as a future hint. Many times angular has own set of tools, and accessing and manipulating the DOM from the component should be a last resort.