0

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;

  }
}

1 Answers1

1

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;
      }
    });

   
  }
}




   
Bikale G
  • 67
  • 4
  • Thank you for your response. I had a few errors in the types of the variables. Could you help me understand the need for flowerList? – Terry Dunlap Jan 06 '22 at 01:35
  • I just used them for the for loop to help me decide which one is clicked as I mentioned on the top this can also be done in another way/dynamically – Bikale G Jan 06 '22 at 01:43
  • @TerryDunlap can u post the error throwing here please and in case did u changed the animation styles state("false", style({ backgroundColor: "" })), state("true", style({ backgroundColor: "blue" })), transition("false<=>true", [animate("0.3s 0.0s ease-in")]) check this https://codesandbox.io/s/tender-antonelli-mi9qn?file=/src/app/app.component.ts – Bikale G Jan 06 '22 at 02:07
  • I am getting a few errors, one is: on flowerClicked: Parameter 'flowerClicked' implicitly has an 'any' type. The second is off of this[varName]: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ChoreListComponent' – Terry Dunlap Jan 06 '22 at 04:18
  • I changed it to use a switch statement then just coded each case with this.ispoop = !this.ispoop. I'm trying to find a way to make it more dynamic, so if i change the names or number of chores the code still functions switch (flowerClicked) { case 'ismorning': { this.ismorning = !this.ismorning; break; } – Terry Dunlap Jan 06 '22 at 04:20
  • Yes it will work but u have to add it to urs switch statements too .if it still throws error share ur code in condsandbox and let’s debug it there – Bikale G Jan 06 '22 at 18:23
  • It is working, thank you for all the help. – Terry Dunlap Jan 06 '22 at 20:09