Michael
Michael

Reputation: 297

How do I auto scroll in Angular?

I got a dynamic component, where I add material cards horizontally. After a few cards, the component gets filled, and I can scroll the component. But how can I make it auto scroll horizontally, so that I don't have to use the mouse all the time?

I already tried playing with some css attributes like overflow and so on.

.blocksWrapper {
  display: flex;
  overflow: auto;
  min-height: 305px;
}

I expect, that it autoscrolls horizontally.

This is how it should look like:

enter image description here

But instead it never scrolls automatically.

Upvotes: 3

Views: 18273

Answers (2)

LPGTE SOFTS
LPGTE SOFTS

Reputation: 175

There are several ways to automatically scroll images:

  1. Move the automatic elements by changing their coordinates with a timer, in this case the animation will be activated even if there is no scrolling.

  2. Use the automatic scrolling of the container with a timer,in this case the animation will be activated only if there is a scolling

Here is an example of automatic scrolling implemented with the first solution.

Html

<div
  id="animation1"
  class="animatedElementsContainerStyle"
  (mouseover)="setAnimationsStatus('pause')"
  (mouseout)="setAnimationsStatus('animate')"
>
  <div id="animatedItem1" class="animatedItem">
    <div class="contentContainer">Item 1</div>
  </div>
  <div id="animatedItem2" class="animatedItem">
    <div class="contentContainer">Item 2</div>
  </div>
  <div id="animatedItem3" class="animatedItem">
    <div class="contentContainer">Item 3</div>
  </div>
  <div id="animatedItem4" class="animatedItem">
    <div class="contentContainer">Item 4</div>
  </div>
  <div id="animatedItem5" class="animatedItem">
    <div class="contentContainer">Item 5</div>
  </div>
  <div id="animatedItem6" class="animatedItem">
    <div class="contentContainer">Item 6</div>
  </div>
</div>

CSS

.animatedElementsContainerStyle {
  height: 160px;
  width: 500px;
  height: 140px;
  overflow-x: hidden;
  overflow-y: hidden;
  white-space: nowrap;
  position: relative;
}

.animatedItem {
  display: inline-block;
  width: 200px;
  height: 130px;
  position: absolute;
  background-color: yellow;
  font-size: 30;
  font-weight: bold;
  margin: 0 auto;
  cursor: pointer;
}
.animatedItem {
  display: inline-block;
}

.contentContainer {
  width: 100;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

TypeScript

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

@Component({
  selector: 'app-horizentral-animation',
  imports: [],
  templateUrl: './horizentral-animation.component.html',
  styleUrl: './horizentral-animation.component.css',
})
export class HorizentralAnimationComponent {
  animationStatus: boolean = true;

  constructor() {}

  ngAfterViewInit() {
    this.startAnimationContainer('animation1');
  }

  startAnimationContainer(containerName: string) {
    let animationContainer = document.getElementById(containerName)!;
    let mapArrayLefts = new Map<string, any>();
    let marginBetweenAnimatedItems = 200;
    let lastElementLeft = 0;
    let isViewInitilized: boolean = false;
    let allAnimatedItemsWidth = 0;
    let containerAnimatedWidth = 0;

    var timer = setInterval(() => {
      let animatedNodes = animationContainer.querySelectorAll<HTMLElement>(
        '#' + containerName + ' .animatedItem'
      );
      containerAnimatedWidth = animationContainer.getBoundingClientRect().width;

      //Init the View before Starting the animation
      if (animatedNodes.length > 0) {
        if (isViewInitilized == false) {
          isViewInitilized = true;

          animatedNodes?.forEach((element, index) => {
            let itemWidth = element.getBoundingClientRect().width;
            allAnimatedItemsWidth = allAnimatedItemsWidth + itemWidth;
          });

          animatedNodes?.forEach((element, index) => {
            if (index == 0 && allAnimatedItemsWidth < containerAnimatedWidth) {
              let elLeft = containerAnimatedWidth + 1;
              element.style.left = elLeft + 'px';
              mapArrayLefts.set(element.id, elLeft);
            } else if (
              index == 0 &&
              allAnimatedItemsWidth > containerAnimatedWidth
            ) {
              let elLeft = 0;
              element.style.left = elLeft + 'px';
              mapArrayLefts.set(element.id, elLeft);
            } else {
              let leftPrecdElement =
                animatedNodes[index - 1]?.getBoundingClientRect().left;
              let leftNewElem = leftPrecdElement + marginBetweenAnimatedItems;
              element.style.left = leftNewElem + 'px';
              mapArrayLefts.set(element.id, leftNewElem);
            }
          });

          lastElementLeft = mapArrayLefts.get(
            animatedNodes[animatedNodes.length - 1].id
          );
        }
      }

      // Starting the Animation

      if (this.animationStatus == true) {
        for (let i = 0; i < animatedNodes!.length; i++) {
          let elLeft = mapArrayLefts.get(animatedNodes[i].id);
          let newElLX = Number.parseFloat(elLeft) - 1;

          mapArrayLefts.set(animatedNodes[i].id, newElLX);
          animatedNodes[i].style.left = newElLX + 'px';
        }

        let topHtmlElement = document.querySelector<HTMLElement>(
          '#' + containerName + ' .animatedItem'
        );
        let topHtmlElementRight = topHtmlElement!.getBoundingClientRect().right;

        if (topHtmlElementRight < 0) {
          topHtmlElement!.style.left = lastElementLeft + 'px';
          animationContainer!.removeChild(topHtmlElement!);
          animationContainer!.appendChild(topHtmlElement!);

          mapArrayLefts.set(topHtmlElement!.id, lastElementLeft);
        }
      }
    }, 10);
  }

  setAnimationsStatus(status: string) {
    if (status == 'pause') {
      this.animationStatus = false;
    }

    if (status == 'animate') {
      this.animationStatus = true;
    }
  }
}

The implementation of this example can be found on stackblitz here .

Upvotes: 0

Kapcash
Kapcash

Reputation: 6909

There is no automatic feature to auto scroll a div when the size changes.
I suppose you dynamically add your cards using some button? Then you could scroll programatically when adding a card!

Here are multiple suggested solutions:

  • You can use jquery's method "scrollLeft()". Just set the horizontal scroll to something like 99999 to be sure it goes as far possible.
  • Change the default scrollTo() behavior of your html element (see this thread).
  • Use the css directive direction: rtl to set the default scroll bar position to the right (see this thread)

Here is an example using the solution 2) : https://angular-dfjmej.stackblitz.io

Maybe it's not the exact render you want, but it's only a matter of settings then.

Upvotes: 3

Related Questions