Why are my animation states being shared among different instances of the component?

Why is the animation playing for both instances of the carousel component when interacting with just one call (e.g. clicking next or prev)?

carousel.component.ts

@Component({
 selector: 'app-carousel',
 standalone: true,
  templateUrl: './carousel.component.html',
  imports:[ CommonModule ],
  styleUrls: ['./carousel.component.scss'],
  animations: [ CarouselAnimation ]
})
export class CarouselComponent {
  @Input() items: string[] = [];
  @Input() itemsPerSlide: number = 0;
  @Input() carouselName:string = "";
  currentIndex: number = 0;
  hasNextItems: boolean = true;

  get groupedItems(): string[][] {
    const result: string[][] = [];
    for (let i = 0; i < this.items.length; i += this.itemsPerSlide) {
      result.push(this.items.slice(i, i + this.itemsPerSlide));
    }
    return result;
  }

  next() {
    const nextIndex = (this.currentIndex + 1) % this.groupedItems.length;
    this.hasNextItems = this.groupedItems[nextIndex].length > 0;
    if (this.hasNextItems) {
      this.currentIndex = nextIndex;
    }
  }

  prev() {
    const prevIndex = (this.currentIndex - 1 + this.groupedItems.length) % this.groupedItems.length;
    const prevItemsPerSlide = this.groupedItems[prevIndex].length;

    if (prevItemsPerSlide > 0) {
      this.hasNextItems = true;
      this.currentIndex = (this.currentIndex - 1 + this.groupedItems.length) % this.groupedItems.length;
    }
  }
}

carousel.component.html

<div id="UniqueDynamicCarousel" class="carousel slide carousel-fade" data-ride="carousel">
  <div class="carousel-inner">
    <div *ngFor="let itemGroup of groupedItems; let i = index" [class.active]="i === currentIndex" class="carousel-item"  [@carouselFade]>
      <div class="d-flex justify-content-around">
        <div *ngFor="let item of itemGroup" class="carousel-inner-item">
          <img class="d-block w-100" [src]="item" alt="Slide {{i + 1}}">
        </div>
      </div>
    </div>
  </div>
  <a class="carousel-prev" href="#UniqueDynamicCarousel" role="button" data-slide="prev" (click)="prev()">
    <div class="icon-container">
      <i class="fa fa-solid fa-arrow-left"></i>
    </div>
  </a>
  <a class="carousel-next" href="#UniqueDynamicCarousel" role="button" data-slide="next" (click)="next()">
    <div class="icon-container">
      <i class="fa fa-solid fa-arrow-right"></i>
    </div>
  </a>
</div>

animations.ts


export const CarouselAnimation = [
  trigger('carouselFade', [
    transition(':enter', [
      style({ opacity: 0 }),
      animate('300ms ease-in', style({ opacity: 1 }))
    ]),
    transition(':leave', [
      animate('300ms ease-out', style({ opacity: 0 }))
    ])
  ])
]

Usage

<h2>Carousel</h2>
<app-carousel [items]="carouselItems" [itemsPerSlide]="3" [carouselName]="'Carousel'"></app-carousel>
<h2>Carousel2</h2>
<app-carousel [items]="carouselItems2" [itemsPerSlide]="3" [carouselName]="'Carousel2'"></app-carousel>

carousel item arrays:

  carouselItems: string[] = [
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
  ];
  carouselItems2: string[] = [
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
    'https://via.placeholder.com/800x400',
  ];
  • Changed the trigger name to be unique.
  • Assigned a unique id to the carousel.
  • Attempted code duplication as a workaround.

Answer №1

Your understanding of change detection seems to be causing issues for you.

Every time there is an interaction with your components, a new groupedItems is created, leading to the recreation of elements and triggering animations on re-entry into the DOM.

To resolve this bug, consider adding ChangeDetectionStrategy.OnPush to prevent change detection from triggering in carousels that have not been interacted with.

@Component({
  ...
  changeDetection: ChangeDetectionStrategy.OnPush,
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Receiving information within an Angular Component (Profile page)

I am currently developing a MEAN Stack application and have successfully implemented authentication and authorization using jWt. Everything is working smoothly, but I am encountering an issue with retrieving user data in the Profile page component. Here ar ...

Error message on Angular 4: "404 - Unable to locate file

Currently, I am working with Angular 4 and attempting to load .csv data. For reference, I have been following this guide: . However, I am facing issues while trying to load the sample.csv file. Despite trying to place the file in src/app, src, or root dire ...

Issue encountered while utilizing an observable object within a FormGroup

I've encountered an issue that I can't seem to resolve. I have a function that is responsible for creating my FormGroup along with the form fields and validators. The validators are custom validators that require a value from an observable, and t ...

Is it possible for me to listen to an AngularJS event using regular JavaScript, outside of the Angular framework?

Is it possible to listen to an event triggered in AngularJS using regular JS (outside of Angular)? I have a scenario where an event is being emitted using RxJS in Angular 2. Can I observe that event from pure JS? Here's some example pseudo code: imp ...

Interactive Bootstrap 4 button embedded within a sleek card component, complete with a dynamic click event

I am trying to create a basic card using bootstrap 4 with the following HTML code. My goal is to change the style of the card when it is clicked, but not when the buttons inside the card are clicked. Currently, clicking on the test1 button triggers both ...

How to Use Hyperledger Composer's Rest-Server-Api Local-Passport Strategy in an Angular Application without Node.js

Is it possible for me to implement the passport-local strategy in my project, considering that I am using an angular front-end generated by the composer-rest-server tool? I noticed in the documentation for passportjs regarding passport-local, it mentions ...

I noticed that while my shareService is effectively sending values in Angular 2, I encounter an issue where my other components are displaying default values instead

I'm in the process of developing an application using angular 2. I have a UserService that sends a value to other components indicating whether a user is logged in or not, and it's working correctly in terms of data transmission. The issue I&apos ...

Determine the value added tax in your online shopping basket

Currently, I am in the process of developing a webshop for a pizzeria using Angular, and recently completed work on my cart component. One of the key features I wanted to incorporate was adding a 10% Value-Added Tax (VAT) for each item in the cart and incl ...

How can I designate the first enum value as 1 in a protobuf data structure?

In order to resolve an issue in the dropdown component of Primeng, the first enum value in protobuf must be set to 0. However, this is causing some trouble. Is there a method to change the first enum value to 1 instead? ...

Tips for sorting queries within a collection view in Mongoose:

I am working with Mongoose and creating a view on a collection. NewSchema.createCollection({ viewOn: originalModel.collection.collectionName, pipeline: [ { $project: keep.reduce((a, v) => ({ ...a, [v]: 1 }), {}), }, ], ...

Unable to execute NPM AUDIT FIX

We are facing a challenge with a Windows PC that has been rebuilt. After successfully cloning the project we were working on, it now refuses to build or compile. The project was an Angular 7 build and everything was running smoothly with NVM installed and ...

Implicated Generic in TypeScript

Is there a way to simplify my class A implementation? export class A<TB extends B<TC>, TC> implements TD<TB, TC> { make(): TC {} } Currently, I have to specify the TC type every time I create an instance of A: class CTest {} class BTes ...

Discovering the generic parameter in the return type using TypeScript

I am struggling with a specific issue export type AppThunk<ReturnType> = ThunkAction< ReturnType, RootState, unknown, Action<string> >; After implementing the above code snippet export const loadCourse = (id: string): AppThunk ...

Confirm that the user has interacted with every input

When it comes to validating a form, you have the ability to determine if a user has interacted with an input field or checkbox (using X.touched). Is there a built-in validator that requires a user to specifically interact with each input field at least onc ...

What is the process for setting the active state for HtmlBodyElement?

I attempted to use the following method: document.querySelector('body').setActive(); However, I encountered an error: TS2339: Property 'setActive' does not exist on type 'HTMLBodyElement'. Any suggestions on how to resolve t ...

Send all Apache requests within a specified URL directory to a particular file, while directing all other requests to a different file

I am in the process of setting up an Angular application along with a basic PHP CRUD API backend on my Raspberry Pi 3 using Apache. My goal is to configure the mod_rewrite rules to first check for existing files or directories, then redirect requests for t ...

Exporting declarations and different export types within a TypeScript ambient module

I am currently working on adding specific types for the config module in our application. The config module is generated dynamically from a JSON file, making it challenging to type. Since it is a node module, I am utilizing an ambient module for the typing ...

The ngx-datatable is designed to bind only to the final comparator

When utilizing templates with ngx-datatable-column and binding comparator functions, only the final bound comparator is applied to all sortable columns. For instance: <div class="m-333"> <button mat-raised-button color="primary" (click)="openP ...

Running into issues compiling Ionic 4 with Angular 7 inside a Docker container

Facing Issues Compiling Ionic 4 with Angular 7 in Docker I am trying to compile a project using Ionic 4 and Angular 7 within Docker. Here are the steps I have taken: I manually created an image with Java JDK version 8, following this article How To Ins ...

Issue with importing MomentJS globally in TypeScript

When it comes to defining global external modules in TypeScript, there is a useful option available. For instance, if you have jQuery library loaded externally, you can set up a global definition without having to include its duplicate in the TypeScript bu ...