2

In Angular 9 animations, how would I trigger a animation from the component itself? I assume I would do this manually in the component itself since it keeps track of the state of when the graph is created. As opposed to using a template expression where the parent would keep track of the state with a data binding and host property.

<div class="chart-body">
  <div *ngFor="let chart of charts | async | daysFilter:7" class="last-seven-days-body">
      <line-chart
        [curve-data]="chart"
        graph-size="med"></line-chart>
  </div>
</div>
@Component({
  selector: 'line-chart',
  templateUrl: './line-chart.component.html',
  styleUrls: ['./line-chart.component.css'],
  animations: [
    trigger('fadeIn', [
      transition('void => *', [
        style({ opacity: 0 }),
        animate(2000, style({opacity: 1}))
      ])
    ])
  ],

})

export class LineChartComponent {
  @Input('curve-data') curveData: Array<object>;
  @Input('graph-size') graphSize: String;


  constructor(
    private lineChartService: LineChartService,
    private elRef: ElementRef,
    private fadeInStart: Boolean,
  ) { }    

  ngAfterViewInit() {
    this.lineChartService.makeGraph(
      this.curveData,
      this.elRef.nativeElement,
      this.graphSize,
    );

    this.fadeInStart = true; //AFTER GRAPH IS MADE, TURN ON FADE IN ANIMATION HERE
  }     
}  
dman
  • 10,406
  • 18
  • 102
  • 201
  • The problem is, to what dom element should the animation be applied? You can still kinda do this, but you’ll need an @trigger on the element the animation need to be applied on. – MikeOne Jun 16 '20 at 20:13
  • I need the animation to be applied on line-chart element – dman Jun 16 '20 at 20:24

1 Answers1

5

Instead of using transition void => *, you could try to give specific names/booleans like false => true and bind it to a member variable. Try the following

line-chart.component.ts

@Component({
  selector: 'line-chart',
  templateUrl: './line-chart.component.html',
  styleUrls: ['./line-chart.component.css'],
  animations: [
    trigger('fade', [
      state('false', style({ opacity: 0 })),
      state('true', style({ opacity: 1 })),
      transition('false => true', animate('2000ms ease-in')),
      transition('true => false', animate('2000ms ease-out'))
    ]),
  ]
})
export class LineChartComponent {
  @Input('curve-data') curveData: Array<object>;
  @Input('graph-size') graphSize: String;

  public fadeInStart = false;    // <-- hide chart by default

  constructor(
    private lineChartService: LineChartService,
    private elRef: ElementRef,
  ) { }    

  ngAfterViewInit() {
    this.lineChartService.makeGraph(
      this.curveData,
      this.elRef.nativeElement,
      this.graphSize,
    );

    this.fadeInStart = true;     // <-- show chart here
  }     
}

line-chart.component.html

<div [@fade]="fadeInStart">
  <!-- chart -->
</div>

Update for Ivy (03/15/21)

ruth
  • 29,535
  • 4
  • 30
  • 57
  • 1
    I am getting `ExpressionChangedAfterItHasBeenCheckedError` for when this.fadeInStart = true is set. Is there any other way to set that after the chart is made? I guess I could run change detection again but was wondering – dman Jun 16 '20 at 23:43
  • 2
    It probably occurs only in `dev` mode. You could try replacing the hook with `ngAfterContentInit()`. – ruth Jun 17 '20 at 07:30
  • you can't use private property fadeInStart in template. Remove 'private' – plusz Mar 15 '21 at 20:48
  • @plusz: The answer was posted without accounting for Ivy where it wouldn't be an issue. I've updated the answer nevertheless. – ruth Mar 15 '21 at 21:59