Search code examples
javascriptangulartypescriptangular-animationsangular13

Angular 13, animate a clicked element while leveraging a single animation block


I am creating a simple, single page site (mostly to learn Angular), and cant seem to figure out how to use a single animation to affect different DOM elements. I could define the animation for each element, but that seems extremely ineffective.

Is there a way to animate the image within the clicked button without defining a separate animation block for each element?

Thank you, Terry

<!-- HTML:   -->  
<button mat-flat-button (click)="finishedChore()">
      <img
        [@openClose]="isOpen ? 'open' : 'closed'"
        src="assets/images/morning.png"
      />
    </button>
    <button mat-flat-button (click)="finishedChore()">
      <img
        [@openClose]="isOpen ? 'open' : 'closed'"
        src="assets/images/poop.png"
      />
    </button>
    <button mat-flat-button (click)="finishedChore()">
      <img
        [@openClose]="isOpen ? 'open' : 'closed'"
        src="assets/images/cleanRoom.png"
      />
    </button>
    <button mat-flat-button (click)="finishedChore()">
      <img
        [@openClose]="isOpen ? 'open' : 'closed'"
        src="assets/images/cleanSinks.png"
      />
    </button>
    <button mat-flat-button (click)="finishedChore()">
      <img
        [@openClose]="isOpen ? 'open' : 'closed'"
        src="assets/images/evening.png"
      />
    </button>
// .ts file
import { Component, OnInit } from '@angular/core';
import {
  trigger,
  state,
  style,
  animate,
  transition,
} from '@angular/animations';

@Component({
  selector: 'app-chore-list',
  templateUrl: './chore-list.component.html',
  styleUrls: ['./chore-list.component.scss'],
  animations: [
    trigger('openClose', [
      state('closed', style({ backgroundColor: '' })),
      state('open', style({ backgroundColor: 'blue' })),
      transition('closed<=>open', [animate('0.3s 0.0s ease-in')]),
    ]),
  ],
})
export class ChoreListComponent implements OnInit {
  isOpen = false;
  constructor() {}
  ngOnInit(): void {}

  finishedChore() {
    this.isOpen = !this.isOpen;

  }
}

Solution

  • yes it is possible to use a single animation block

    here the issue is you are using single isOpen variable and single finishedChore() function that affects this variable so when one of the buttons is clicked it will change for all of them so my suggestion would be look like this

    <button mat-flat-button (click)="finishedChore('morning')">
      <img [@openClose]="ismorning" src="assets/images/morning.png" />
    </button>
    <button mat-flat-button (click)="finishedChore('poop')">
      <img [@openClose]="ispoop" src="assets/images/poop.png" />
    </button>
    <button mat-flat-button (click)="finishedChore('cleanRoom')">
      <img [@openClose]="iscleanRoom" src="assets/images/cleanRoom.png" />
    </button>
    <button mat-flat-button (click)="finishedChore('cleanSinks')">
      <img [@openClose]="iscleanSinks" src="assets/images/cleanSinks.png" />
    </button>
    <button mat-flat-button (click)="finishedChore('evening')">
      <img [@openClose]="isevening" src="assets/images/evening.png" />
    </button>
     
    

    the .ts file

    import { Component, OnInit } from "@angular/core";
    import {
      trigger,
      state,
      style,
      animate,
      transition
    } from "@angular/animations";
    
    @Component({
      selector: "app-root",
      templateUrl: "./app.component.html",
    
      animations: [
        trigger("openClose", [
          state("false", style({ backgroundColor: "" })),
          state("true", style({ backgroundColor: "blue" })),
          transition("false<=>true", [animate("0.3s 0.0s ease-in")])
        ])
      ]
    })
    export class ChoreListComponent implements OnInit {
      //flower list can be done dynamically 
      isevening = false;
      iscleanSinks = false;
      ismorning = false;
      ispoop = false;
      iscleanRoom = false;
      flowerList = ["morning", "poop", "cleanSinks", "cleanRoom", "evening"];
    
      ngOnInit(): void {}
    
      finishedChore(flowerClicked) {
        this.flowerList.forEach((flowername) => {
          let varName = "is" + flowername; // assume this as "is"+'noop'=>isnoop
          console.log(varName);
          if (flowerClicked == flowername) {
            this[varName] = !this[varName];
          } else {
            this[varName] = false;
          }
        });
    
       
      }
    }