3
votes

I would like to fire two animations at the same time on click. The animation triggers use the same state, one is placed on an outer parent div and the other is nested within this div. The style changes are made, but the transition is applied only on the parent component. I've used animateChild within my parent animation with no luck. How can I apply an animation both a parent and child element?

animations.ts

import {
  trigger,
  state,
  style,
  transition,
  animate,
  query,
  group,
  animateChild,
} from "@angular/animations";

export const Animations = {
  animations: [
    trigger("expansionTrigger", [
      state(
        "true",
        style({
          height: "*"
        })
      ),
      state(
        "false",
        style({
          height: "0",
          display: "none"
        })
      ),
      transition("false <=> true", [
        group([
          query("@colExpansion", [animateChild()]),
          animate("3s ease")
        ])
      ])
    ]),
    trigger("colExpansion", [
      state(
        "true",
        style({
          "-webkit-box-flex": "0",
          flex: "0 0 66.66667%",
          "max-width": "66.66667%"
        })
      ),
      state(
        "false",
        style({
          "flex-basis": "0",
          "-webkit-box-flex": "1",
          "flex-grow": "1",
          "max-width": "100%"
        })
      ),
      transition("false <=> true", animate(3))
    ])
  ]
};

body.component.ts

import { Component, Input } from '@angular/core';
import { Animations } from '../animations';

@Component({
  selector: 'app-body',
  templateUrl: './body.component.html',
  styleUrls: ['./body.component.css'],
  animations: Animations.animations
})
export class BodyComponent  {

  @Input() isExpanded: string;

}

body.component.html

<div [@expansionTrigger]="isExpanded === 'true' ? 'true' : 'false'">
    <div [@colExpansion]="isExpanded === 'true' ? 'true' : 'false'">
    </div>
</div>
1
Did you figure this out as I have the same issue. - Ross Rawlins

1 Answers

0
votes

I made a working demo. I did my own styles, as I don't understad the purpose of this component. You can easily adapt it to your styles...

animations.ts

import {
    trigger,
    state,
    style,
    transition,
    animate,
    query,
    group,
    animateChild,
    keyframes,
} from "@angular/animations";
//
// Global Animate Time
const animateTime0 = "1s ease"
const animateTime1 = "3s"
const animateTime2 = "200ms ease-in-out"
//
// Global Animations
const fade0 = animate(animateTime2, keyframes([
    style({ opacity: 0 }),
    style({ opacity: 1 })
]))
//
// Styles
// Expansion Trigger
const expansionTriggerOnStyle = {
    height: "*",
    display: "*"
}
const expansionTriggerOffStyle = {
    height: "0",
    display: "none"
}
// Col.
const colExpansionOnStyle = {
    width: "66.66667%"
}
const colExpansionOffStyle = {
    width: "100%"
}
//
// Animations
// Expansion Trigger
function expansionTriggerAni(start, end) {
    return group([
        animate(animateTime0, keyframes([
            style(start),
            style(end)
        ])),
        query("@colExpansion", group([
            animateChild(),
            fade0
        ]))
    ])
}
//
// *Exported* Triggers
export const expansionTriggerAnimation = trigger("expansionTrigger", [
    //
    // States
    state("on", style(expansionTriggerOnStyle)),
    state("off", style(expansionTriggerOffStyle)),
    //
    // Transitions
    transition(
        "on => off",
        expansionTriggerAni(expansionTriggerOnStyle, expansionTriggerOffStyle)
    ),
    transition(
        "off => on",
        expansionTriggerAni(expansionTriggerOffStyle, expansionTriggerOnStyle)
    )
])
export const colExpansionAnimation = trigger("colExpansion", [
    //
    // States
    state("on", style(colExpansionOnStyle)),
    state("off", style(colExpansionOffStyle)),
    //
    // Transitions
    transition("on <=> off", animate(animateTime1))
])

body.component.ts

import { Component, OnInit } from '@angular/core';
import { expansionTriggerAnimation, colExpansionAnimation } from './animations';

@Component({
  selector: 'body',
  templateUrl: './body.component.html',
  styleUrls: ['./body.component.scss'],
  animations: [
    expansionTriggerAnimation,
    colExpansionAnimation
  ]
})
export class BodyComponent implements OnInit {
  isExpanded: boolean
  status: string = 'off'

  constructor() { }

  ngOnInit() {
  }

  toggle() {
    this.isExpanded = !this.isExpanded
    this.status = !this.isExpanded ? 'off' : 'on'

    console.log("Status:", this.status)
  }

}

body.component.scss

.wrapper {
    width: 200px;
    height: 50px;

    background-color: gray;
    cursor: pointer;

    overflow: hidden;

    .col {
        width: 100%;
        background-color: beige;
    }
}

body.component.html

<button (click)="toggle()">Toggle expansion</button>

<div class="wrapper" [@expansionTrigger]="status">
    <div class="col" [@colExpansion]="status">
        I am col
    </div>
</div>

When expanded