Search code examples
htmlcssangularangular-animations

Angular: custom state animation not working as expected


I have two divs (parent and child) and I want to do a special animation based on custom state (close => open && open => close):

  • when the state goes from close => open:
    I want the parent div's opacity to go from 0 to 1 and the child's scale to go from 0.3 to 1.
  • when the state goes from open => close:
    I want the css attributes to return to their original values (opacity 0 for the parent and scale(0.3) for the child)

The good news is the animation works as expected (for both divs) when the state goes => close => open.

The bad news is the animation is not working (only for the child div) when the state goes from open => close.

Enough talking, here is what I did:

The view HTML:

<div [@openClose]="opened ? 'open' : 'close'" class="parent">
    <div [@animateChild]="opened ? 'open' : 'close'" class="child">
     <p>Child content</p>
    </div>
</div>

In the component.ts:

@Component({
  selector: 'app-my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.css'],
  animations: [
    trigger('openClose', [
        state('open', style({
           opacity: 1,
           visibility: 'visible',
        })),
        // when we go from close to open do these steps
        transition('close => open', [
          query(':self', [// animate div itself
              animate('200ms ease-in', style({
                opacity: 1,
                visibility: 'visible',
              }))
          ]),
          query('@animateChild', animateChild())// then animate children (.child)
        ]),

        transition('open => close', [
          query(':self', animate('200ms ease-in')),
          query('@animateChild', animateChild()),
        ]),
    ]),
    trigger('animateChild', [
       state('open', style({ opacity: 1, transform: 'scale(1)' })),
       transition('close => open', [
         animate('100ms ease-out')
       ]),

       transition('open => close', [
         style({ transform: 'scale(0.3)', opacity: 0 }),
         animate('100ms ease-out')
       ])
    ])
  ]
})
export class MyComponent implements OnInit {
  opened: boolean;
  constructor() { }

  ngOnInit() {}

  open(){
    this.opened = true;
  }

  close(){
    this.opened = false;
  }
}

In the CSS file:

.parent{
  width: 100%;
  height: 100vh;
  background: black;
  opacity: 0;/* initialize opacity to 0 for the parent */
}
.child{
   width: 50%;
   background: white;
   transform: scale(0.3);/* initialize scale to 0.3 for the child */
   opacity: 0; /* and opacity to 0 to be invisible when component initialized */
}

This is the example on Stackblitz:
https://stackblitz.com/edit/angular-bjuzyr

What I did wrong here ?


Solution

  • Would you please try the below animation code:

      animations: [
    trigger('openClose', [
        state('open', style({
           opacity: 1,
           visibility: 'visible',
        })),
        state('close', style({
           opacity: 0,
           visibility: 'visible',
        })),
        // when we go from close to open do these steps
        transition('* => *', [
          animate('200ms ease-in'),
        ]),
    ]),
    trigger('animateChild', [
       state('open', style({ opacity: 1, transform: 'scale(1)' })),
       state('close', style({ opacity: 0, transform: 'scale(0.3)' })),
       transition('* => *', [
         animate('100ms ease-out')
       ])
    ])
    ]