angularanimation

Angular Animation For Dynamically Changing Height


I've successfully gotten a panel to animate expanding and closing when entering and leaving the DOM. The problem is I now have a busy indicator inside the panel prior to showing details, and the animation only occurs for opening the busy indicator, and snaps when the detail content is shown.

How can I get the Angular animation to animate on any height change?

I have an example here: https://stackblitz.com/edit/angular-animation-for-dynamically-changing-height?embed=1&file=src/app/app.component.ts

trigger('expandCollapseDetails', [
    state('void', style({
        'height': '0px',
        overflow: 'hidden'
    })),
    //element being added into DOM.
    transition(':enter', [
        animate('500ms ease-in-out', style({
            'height': '*',
            overflow: 'hidden'
        }))
    ]),
    //element being removed from DOM.
    transition(':leave', [
        animate('500ms ease-in-out', style({
            'height': '0px',
            overflow: 'hidden'
        }))
    ])
])

Solution

  • I've written a component that smoothly animates the height of projected content if that content changes. It's used like this:

    <smooth-height [trigger]="content">
      {{content}}
    </smooth-height>
    

    Here's a stackblitz: https://stackblitz.com/edit/angular4-kugxw7

    This is the component:

    import {ElementRef, HostBinding, Component, Input, OnChanges} from '@angular/core';
    import {animate, style, transition, trigger} from "@angular/animations";
    
    @Component({
      selector: 'smooth-height',
      template: `
        <ng-content></ng-content>
      `,
      styles: [`
        :host {
          display: block;
          overflow: hidden;
        }
      `],
      animations: [
        trigger('grow', [
          transition('void <=> *', []),
          transition('* <=> *', [
            style({height: '{{startHeight}}px', opacity: 0}),
            animate('.5s ease'),
          ], {params: {startHeight: 0}})
        ])
      ]
    })
    export class SmoothHeightComponent implements OnChanges {
      @Input()
      trigger: any;
    
      startHeight: number;
    
      @HostBinding('@grow') grow: any;
    
      constructor(private element: ElementRef) {}  
                  
      ngOnChanges(){
        this.startHeight = this.element.nativeElement.clientHeight;
    
        this.grow = {
          value: this.trigger,
          params: {startHeight: this.startHeight}
        };
      }
    }