Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 scroll two seperate elements togther

Tags:

angular

I have a demo here

I'm capturing the scrollLeft of one element as it's scrolled.

Is it possible to update the second div with the scrollLeft number so both div scroll left and right together?

The elements have to be separate but I need them to scroll together.

Or is there a simpler way to do this in Angular.

I had this working outside of Angular with jQuery but I don't want to use jQuery in Angular.

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 5';
  isNavbarCollapsed = true;

  private scrollLeft: number
  //private scrolLTwo: HTMLElement = 

  onScroll(event: Event) {
    this.scrollLeft = (event.target as HTMLElement).scrollLeft;
    //console.log(this.scrollLeft);
    this.updateScroll();
  }

  updateScroll(){
    //Update second scrolling element
  }
}
like image 241
ttmt Avatar asked Apr 30 '18 15:04

ttmt


2 Answers

You can just get a reference to the second <div> and set it's scroll left to the same amount:

<div class="container" (scroll)="scrollTwo.scrollLeft = scrollOne.scrollLeft" #scrollOne>
    ...
</div>
<div class="container" #scrollTwo>
    ...
</div>

If you want to have more complicated logic in your component to manage what the scroll amount should be, you can just get the reference to the two DOM nodes via @ViewChild:

<div class="container" (scroll)="updateScroll()" #scrollOne>
    ...
</div>
<div class="container" #scrollTwo>
    ...
</div>
@Component(...)
export class AppComponent  {
  @ViewChild('scrollOne') scrollOne: ElementRef;
  @ViewChild('scrollTwo') scrollTwo: ElementRef;

  updateScroll(){
    const scrollOne = this.scrollOne.nativeElement as HTMLElement;
    const scrollTwo = this.scrollTwo.nativeElement as HTMLElement;

    // do logic and set
    scrollTwo.scrollLeft = scrollOne.scrollLeft;
  }
}

You don't have to get the references via @ViewChild. You could rather just pass them into the method that is called:

<div class="container" (scroll)="updateScroll(scrollOne, scrollTwo)" #scrollOne>
    ...
</div>
<div class="container" #scrollTwo>
    ...
</div>
@Component(...)
export class AppComponent  {
  updateScroll(scrollOne: HTMLElement, scrollTwo: HTMLElement){
    // do logic and set
    scrollTwo.scrollLeft = scrollOne.scrollLeft;
  }
}
like image 52
Daniel W Strimpel Avatar answered Nov 23 '22 07:11

Daniel W Strimpel


Angular CDK now provides cdkScrollable and ScrollDispatcher. Just add cdkScrollable directive to all your scrollable elements which need to be kept in sync and then add this logic to your component:

this.scrollDispatcher.scrolled().subscribe((scrollable: CdkScrollable) => {
  if (typeof scrollable == 'undefined') {
    return true;
  }
  const left = scrollable.measureScrollOffset('left');

  Array.from(this.scrollDispatcher.scrollContainers.keys())
    .filter(otherScrollable => otherScrollable && otherScrollable !== scrollable)
    .forEach(otherScrollable => {
      if (otherScrollable.measureScrollOffset('left') !== left) {
        otherScrollable.scrollTo({left});
      }
    });
});

Do not forget to unsubscribe from this subscription when the component is destroyed. And also inject ScrollDispatcher service in the constructor:

public constructor(private scrollDispatcher: ScrollDispatcher) {}
like image 27
livthomas Avatar answered Nov 23 '22 09:11

livthomas