3

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.

3
  • Can you please clarify- do you mean so that you don't have to click the scrollbar with the mouse, or are you trying to have the code do some auto scrolling? If the mouse is the problem, shift + scroll wheel is horizontal, or most trackpads support the multi touch gesture. Commented Jan 22, 2019 at 12:15
  • No. What I mean: The component always stays at the same spot, even when I add more cards. What I want: It should always scroll to the right automatically, so that the most recent card gets shown. But of course scrolling with the mouse should be possible too. I hope you know what I mean. Commented Jan 22, 2019 at 12:34
  • I was looking at this stackblitz stackblitz.com/edit/… from this answer stackoverflow.com/questions/43945548/…, can you have a no size element after that you always call scrollIntoView on when you add a card? Commented Jan 25, 2019 at 13:38

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

How do I use scrollLeft() in TypeScript? Can you give me an example?
I edited my answer with a stackblitz link where you can find a solution.
You should suggest developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView instead of trying to scroll it manually
0

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 .

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.