Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll buttons in angular application

[Sorry for my bad English]

I have to create scrollable view, with scroll buttons, like this picture:

Spec:

  • When the list is overflow, then show right/left buttons.
  • When there is not overflow, hide the scroll buttons.
  • When the scrollLeft === 0 then disable the left button. and also, when the scrollLeft value is max, then disable the right button.

This is my try:

Template:
<section class="list-with-scroll">

    <div class="list" #list>
        <div *ngFor="let i of items" class="item">{{i}}</div>
    </div>

    <button class="scroller" *ngIf="isOverflown(list)" [class.disable]="!canScrollStart(list)" (click)="scroll(list,-1)" id="scroll-left">&#8678;</button>

    <button class="scroller" *ngIf="isOverflown(list)" [class.disable]="!canScrollEnd(list)" (click)="scroll(list,1)">&#8680;</button>
</section>

Component:

export class AppComponent {
  items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"];

  isOverflown(element: HTMLElement) {
    return element.scrollWidth > element.clientWidth;
  }

  scroll(element: HTMLElement, direction: number) {
    element.scrollLeft += 100 * direction;
  }

  canScrollStart(element: HTMLElement) {
    return element.scrollLeft > 0;
  }

  canScrollEnd(element: HTMLElement) {
    return element.scrollLeft < element.scrollWidth;
  }
}

CSS:
/* The rest of css see on staclblitz */

#scroll-left{
  order: -1; /* To pevent ExpressionChangedAfterItHasBeenCheckedError */
}

StackBlitz: https://stackblitz.com/edit/my-angular-scroll

The help I need:

  • I feel that my solution is very ugly.
  • When whe window/viewport resized, it doesn't update the state of buttons. I can listen to all events, but i don't know hou what is the best way do to it.
  • I don't know how to disable the right button when the scrollLeft value is max. Resolved. Thanks to @Void Spirit

Thenk you for any help.

like image 702
JudahA Avatar asked Aug 11 '26 20:08

JudahA


1 Answers

I think I found the best approach: using directive.

Directive:

import { Directive, ElementRef, HostListener } from "@angular/core";

@Directive({
  selector: "[appScrollable]",
  exportAs: "appScrollable"
})
export class ScrollableDirective {
  constructor(private elementRef: ElementRef) {}

  @Input() scrollUnit: number;

  private get element() {
    return this.elementRef.nativeElement;
  }

  get isOverflow() {
    return this.element.scrollWidth > this.element.clientWidth;
  }

  scroll(direction: number) {
    this.element.scrollLeft += this.scrollUnit * direction;
  }

  get canScrollStart() {
    return this.element.scrollLeft > 0;
  }

  get canScrollEnd() {
    return this.element.scrollLeft + this.element.clientWidth != this.element.scrollWidth;
  }

  @HostListener("window:resize")
  onWindowResize() {} // required for update view when windows resized
}

Usage:

<section class="list-with-scroll">

    <div class="list" appScrollable #list="appScrollable" [scrollUnit]="150">
        <div *ngFor="let i of items" class="item">{{i}}</div>
    </div>

    <button id="scroll-left" class="scroller" *ngIf="list.isOverflow"
  [class.disable]="!list.canScrollStart" (click)="list.scroll(-1)">&#8678;</button>

    <button class="scroller" *ngIf="list.isOverflow"  [class.disable]="!list.canScrollEnd" (click)="list.scroll(1)">&#8680;</button>
</section>

stackBlitz: https://stackblitz.com/edit/my-angular-scroll-better

like image 170
JudahA Avatar answered Aug 13 '26 12:08

JudahA



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!