AMM
AMM

Reputation: 33

Angular17: Staggering Animation

I just created my first angular project, and am trying to use Angular Animations to animate my content on scroll (I want content to appear as I scroll through the page) and also add a staggering animation.

for some reason its not working with me, and given that angular 17 is new and came with a lot of changes I couldn't find enough resources for examples.

Component HTML File:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    @defer (on viewport;){
    <div class="grid grid-items" [@staggerAnimation]="projects.length">
        @for (project of projects; track project.id;) {
        <div class="container">
            <h4>{{project.name}}</h4>
            <p>
                {{project.description}}
            </p>
            <a class="explore-btn" href="{{project.link}}" target="_blank">Explore</a>
        </div>
        }
    </div>
    } @placeholder {
    <div>Loading Projects...</div>
    }
</body>

</html>

Component TS File:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { provideAnimations } from '@angular/platform-browser/animations';
import {
  trigger,
  transition,
  query,
  stagger,
  animate,
  keyframes,
  style,
} from '@angular/animations';

@Component({
  selector: 'app-project-card',
  standalone: true,
  imports: [],
  templateUrl: './project-card.component.html',
  styleUrl: './project-card.component.css',
  providers: [],
  animations: [ 
    trigger('staggerAnimation', [
      transition('* => *', [
        query(':enter', style({opacity: 0}), {optional: true}),
        query(':enter', stagger('300ms', [
          animate('1s ease-in', keyframes([
            style({opacity: 0, transform: 'translateY(-75px)', offset: 0}),
            style({opacity: 0.5, transform: 'translateY(35px)', offset: 0.3}),
            style({opacity: 1, transform: 'translateY(0)', offset: 1}),
          ]))
        ]))
      ])
    ])
  ],
})
export class ProjectCardComponent {

  projects = [ PROJECT OBJECTS HERE]

bootstrapApplication(ProjectCardComponent, {
  providers: [provideAnimations()],
});

*Am using a standalone project in angular 17 so there is no need for NgModule file

I tried placing the trigger at the div with "container" and still didn't work.
I also tried removing the @defer which still lead to nothing.

Not sure if it's relevant but this component is a child component.

Upvotes: 3

Views: 1030

Answers (1)

Naren Murali
Naren Murali

Reputation: 56420

First problem was that the animation was not added in the html, it was done with [@staggerAnimation]="projects.length"

After that, please move the defer up to the main div, this was causing the animations to not work, please find below a working example!

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { provideAnimations } from '@angular/platform-browser/animations';
import {
  trigger,
  transition,
  query,
  stagger,
  animate,
  keyframes,
  style,
} from '@angular/animations';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  providers: [],
  template: `
  @defer (on viewport;){
    <div class="grid grid-items"  [@staggerAnimation]="projects.length">
        @for (project of projects; track project.id;) {
        <div class="container">
            <h4>{{project.name}}</h4>
            <p>
                {{project.description}}
            </p>
            <a class="explore-btn" href="{{project.link}}" target="_blank">Explore</a>
        </div>
        }
    </div>
        } @placeholder {
        <div>Loading Projects...</div>
        }
    <button (click)="add()">add</button>
  `,
  animations: [
    trigger('staggerAnimation', [
      transition('* => *', [
        query(':enter', style({ opacity: 0 }), { optional: true }),
        query(
          ':enter',
          stagger('300ms', [
            animate(
              '1s ease-in',
              keyframes([
                style({
                  opacity: 0,
                  transform: 'translateY(-75px)',
                  offset: 0,
                }),
                style({
                  opacity: 0.5,
                  transform: 'translateY(35px)',
                  offset: 0.3,
                }),
                style({ opacity: 1, transform: 'translateY(0)', offset: 1 }),
              ])
            ),
          ])
        ),
      ]),
    ]),
  ],
})
export class App {
  name = 'Angular';
  id = 5;
  projects = [
    { name: 'test', description: 'test', link: 'https://google.com', id: 1 },
    { name: 'test', description: 'test', link: 'https://google.com', id: 2 },
    { name: 'test', description: 'test', link: 'https://google.com', id: 3 },
    { name: 'test', description: 'test', link: 'https://google.com', id: 4 },
    { name: 'test', description: 'test', link: 'https://google.com', id: 5 },
  ];

  add() {
    this.id = this.id++;
    this.projects.push({
      name: 'test',
      description: 'test',
      link: 'https://google.com',
      id: this.id,
    });
  }
}

bootstrapApplication(App, {
  providers: [provideAnimations()],
});

stackblitz

Upvotes: 4

Related Questions