Angular Delight: Jaw-Dropping Animation

After setting up my first Angular project, I wanted to incorporate Angular Animations to bring life to my content as the user scrolls through the page. I aimed to not only have the content appear on scroll but also implement a staggering animation effect.

However, I encountered some difficulties along the way. With Angular 17 being relatively new and having undergone several changes, I struggled to find adequate resources or examples that could assist me in achieving the desired animation effects.

Here is a snippet of the 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>

This is how the Component TS File looked like:

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()],
});

*Note: As this is a standalone project in angular 17, there is no need for NgModule file

I attempted placing the trigger at the div with "container" without success. Removing the @defer attribute also did not yield any results.

While unsure of its relevance, it's worth mentioning that this component serves as a child component within the project structure.

Answer №1

The initial issue was the absence of animation in the HTML code, which was instead implemented using

[@staggerAnimation]="projects.length"

Furthermore, it is recommended to move the 'defer' attribute up to the main div as this was causing the animations to not function correctly. A functional example is provided below!

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()],
});

Check out the demo on stackblitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a channel for communication between sibling components in Angular 4 by storing component references in a shared service

I am searching for a way to establish communication between two sibling Angular 4 components. After reviewing the documentation at https://angular.io/guide/component-interaction, my idea revolves around utilizing a service that stores a reference to the c ...

Tips on turning off automatic positioning in Bootstrap 4.1

My dropdown list is currently quite large. Take a look at the image linked below. Image How can I address this issue effectively? I'm considering utilizing JavaScript to reposition the menu. Any guidance on how to disable auto-positioning? Check ou ...

Changing the way in which text is selected and copied from a webpage with visible white space modifications

After working on developing an HTML parser and formatter, I have implemented a new feature that allows whitespace to be rendered visible by replacing spaces with middle dot (·) characters and adding arrows for tabs and newlines. You can find the current ...

What is the best way to retrieve TemplateRef from an Angular component?

TS Component ngOnInit() { if(somecondition) // The line of code that is causing issues this.openModal(#tempName); } HTML Component <ng-template #tempName> Content goes here! </ng-template> this.openModal(#tempNa ...

Why might a responsive website automatically switch to mobile view?

My website has a responsive grid system that utilizes media queries with breakpoints. However, I am encountering an issue on IE8 where the "mobile version" of the site is being displayed as the default view even when the screen size is set to what should b ...

Creating a generic union type component in Typescript/Angular 10

My interfaces are as follows: export interface Channel { id: number; name: string; } export interface TvChannel extends Channel { subscribed: boolean; } export interface RadioChannel extends Channel { // marker interface to distinguish radio chan ...

Angular's custom reactive form validator fails to function as intended

Struggling to incorporate a customized angular validator to check for date ranges. The validator is functioning correctly and throwing a validation error. However, the issue lies in the fact that nothing is being displayed on the client side - there are n ...

receiving null instead of an identifier

Attempting to perform an update operation in Angular. Upon submission after updating, a random number is displayed at the end of the API rather than the specific id number. The request URL appears as follows Request URL: http://localhost:4200/api/auth/rol ...

Is it possible to create my TypeORM entities in TypeScript even though my application is written in JavaScript?

While I find it easier to write typeorm entities in TypeScript format, my entire application is written in JavaScript. Even though both languages compile the same way, I'm wondering if this mixed approach could potentially lead to any issues. Thank yo ...

Begin your journey with Foundation Navigation as it seamlessly transitions from left to right

I am currently working on this navigation: I am trying to modify the behavior of the hamburger menu so that when it is clicked, it slides from left to right instead of its current downward motion. Additionally, I would like to adjust the width of the menu ...

When padding is added on an MVC 5 page, the Bootstrap 4.1.1 class option for rounded-circle becomes distorted

Incorporating VS 2017 and bootstrap 4.1.1 into an MVC 5 page, I am facing a challenge in adding right-side padding to an image without distorting the circular shape of the image, as shown below. When I apply the padding, the circle becomes warped, but remo ...

The white background of the div conceals the shadow of the Bootstrap navbar

I am using Bootstrap's navbar with .shadow-sm. I have two divs beneath it, one without background and the other one with a white background. The shadow appears as expected in the div with no background specified, but it is being obscured by the white ...

how to target the last child element using CSS commands

<a><div class="myDiv"></div></a> <a><div class="myDiv"></div></a> <a><div class="myDiv"></div></a> <a><div class="myDiv"></div></a> // This specific one is what ...

A way to navigate through a JSON result without the need for ngFor in Angular

Upon receiving JSON data from the backend, I am presented with the following result: [ { "status":"RUN", "numberOfTurbines":1 }, { "status":"ERROR", "numberOfTurbines&q ...

Is it feasible to exclusively apply Twitter Bootstraps .navbar-fix-to-top on mobile devices?

I am working on a website using Twitter Bootstrap 3 and I have implemented the following navbar: <div class="col-xs-12 col-md-10 col-md-offset-1"> <nav class="navbar navbar-inverse" role="navigation"> <div class="navbar-header"> ...

"Transferring a JavaScript variable to Twig: A step-by-step guide for this specific scenario

When it comes to loading a CSS file based on the user's selected theme, I encountered an issue while trying to implement this in my Symfony application using Twig templates. The code worked flawlessly on a simple HTML page, but transferring it to a Tw ...

Modify the attributes of a CSS class according to the chosen theme (selected within the user interface) in Angular 8

I have a custom-built application with Angular 8 where users can switch between two unique themes in the user interface. I have a specific div class that I want to change the background-color for each theme, but unfortunately I am having difficulty achievi ...

Error: ajax is not defined and needs to be declared (repeated twice)

Currently, I have a form that requires processing using Ajax. <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script> <div class="column1"> <form class="form box" action="javascript:networkCheck();" ...

The Vue 3 Composition API - The property retrieved by setup() "is accessed during rendering but is not defined in the instance."

I've been experimenting with Vue 3's Composition API by creating a small in-app message console, but I'm having trouble pinpointing the error in my code. When rendering this component, the state is being accessed during render (in the loop), ...

Retrieve input from text field and showcase in angular 6 with material design components

Take a look at the output image . In the code below, I am displaying the contents of the messages array. How can I achieve the same functionality with a text box and button in an Angular environment? <mat-card class="example-card"> <mat-car ...