Angular (4, 5, 6, 7) - An easy guide to implementing slide in and out animations using ngIf

How can you implement a basic sliding animation in Angular4 to show and hide a container element?

For example:

<div *ngIf="show">
    <!-- Content -->
</div>

Slide the content in (similar to jQuery's slideDown() method) from top to bottom when show becomes true.

Slide the content out smoothly with an ease-out effect when show becomes false.

Answer №1

First we have some code, followed by an explanation. If you want more details, the official documentation can be found here.

import { trigger, transition, animate, style } from '@angular/animations'

@Component({
  ...
  animations: [
    trigger('slideInOut', [
      transition(':enter', [
        style({transform: 'translateY(-100%)'}),
        animate('200ms ease-in', style({transform: 'translateY(0%)'}))
      ]),
      transition(':leave', [
        animate('200ms ease-in', style({transform: 'translateY(-100%)'}))
      ])
    ])
  ]
})

In your HTML template:

<div *ngIf="visible" [@slideInOut]>When the 'visible' value changes between true and false, this element will smoothly slide up and down.</div>

The angular animation concept may seem complex at first, but once you get the hang of it, it becomes straightforward and powerful.

Breaking down the animation in simpler terms:

  • We're calling this animation 'slideInOut'.

  • For adding the element (:enter), we perform the following actions:

  • ->Initially shift the element 100% upwards (relative to itself) to make it appear off-screen.

  • ->Then gradually animate the translateY value until it reaches 0%, where the element naturally belongs.

  • When removing the element, animate the translateY value (currently at 0) to -100% (off-screen).

Our chosen easing function is ease-in, taking 200 milliseconds – feel free to alter this according to your preferences.

Answer №2

I provided a solution to a similar question previously, and here is one way to achieve it:

Start by creating a file where you define your animations and export them for clarity in your app.component.ts

In the example below, I set the max-height of the div to transition from 0px (when hidden) to 500px, but adjust as needed.

This animation utilizes states (in and out) which toggle upon clicking a button triggering the animation.

animations.ts

import { trigger, state, style, transition,
    animate, group, query, stagger, keyframes
} from '@angular/animations';

export const SlideInOutAnimation = [
    trigger('slideInOut', [
        state('in', style({
            'max-height': '500px', 'opacity': '1', 'visibility': 'visible'
        })),
        state('out', style({
            'max-height': '0px', 'opacity': '0', 'visibility': 'hidden'
        })),
        transition('in => out', [group([
            animate('400ms ease-in-out', style({
                'opacity': '0'
            })),
            animate('600ms ease-in-out', style({
                'max-height': '0px'
            })),
            animate('700ms ease-in-out', style({
                'visibility': 'hidden'
            }))
        ]
        )]),
        transition('out => in', [group([
            animate('1ms ease-in-out', style({
                'visibility': 'visible'
            })),
            animate('600ms ease-in-out', style({
                'max-height': '500px'
            })),
            animate('800ms ease-in-out', style({
                'opacity': '1'
            }))
        ]
        )])
    ]),
]

In your app.component, import the above animation and create a method toggling the animation state.

app.component.ts

import { SlideInOutAnimation } from './animations';

@Component({
  ...
  animations: [SlideInOutAnimation]
})
export class AppComponent  {
  animationState = 'in';

  ...

  toggleShowDiv(divName: string) {
    if (divName === 'divA') {
      console.log(this.animationState);
      this.animationState = this.animationState === 'out' ? 'in' : 'out';
      console.log(this.animationState);
    }
  }
}

Your app.component.html should resemble the following:

<div class="wrapper">
  <button (click)="toggleShowDiv('divA')">TOGGLE DIV</button>
  <div [@slideInOut]="animationState" style="height: 100px; background-color: red;">
  THIS DIV IS ANIMATED</div>
  <div class="content">THIS IS CONTENT DIV</div>
</div>

slideInOut refers to the animation trigger specified in animations.ts

For reference, here is a StackBlitz demonstration:

To address any potential errors prompting you to add BrowserAnimationsModule, simply import it in your app.module.ts:

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  imports: [ ..., BrowserAnimationsModule ],
  ...
})

Answer №3

In response to the initial query, it is actually possible to achieve the desired outcome in Angular by simply adding a class to the DOM element when the show variable is true and handling the animation/transition through CSS.

The bare minimum Angular code required for this is as follows:

<div class="box-opener" (click)="show = !show">
    Open/close the box
</div>

<div class="box" [class.opened]="show">
    <!-- Content -->
</div>

To make this solution work, you will need to define CSS rules for the transition like so:

.box {
    background-color: #FFCC55;
    max-height: 0px;
    overflow-y: hidden;
    transition: ease-in-out 400ms max-height;
}

.box.opened {
    max-height: 500px;
    transition: ease-in-out 600ms max-height;
}

If you encounter compatibility issues with older browsers, don't forget to include vendor prefixes in the transition properties.

For an example demonstration, check out this link

Answer №4

The top-voted solution does not incorporate a genuine slide in/out effect, for the following reasons:

  1. There is no smooth transition for the height attribute. The element starts with 100% of its height at time zero, causing a sudden jump in the elements below.
  2. During sliding out/up, the element uses translateY(-100%) and then abruptly vanishes, creating another disruption in the elements below it.

To achieve a proper slide in and slide out, consider the following implementation:

my-component.ts

import { animate, style, transition, trigger } from '@angular/animations';

@Component({
  ...
  animations: [
    trigger('slideDownUp', [
      transition(':enter', [style({ height: 0 }), animate(500)]),
      transition(':leave', [animate(500, style({ height: 0 }))]),
    ]),
  ],
})

my-component.html

<div @slideDownUp *ngIf="isShowing" class="box">
  I am the content of the div!
</div>

my-component.scss

.box {
  overflow: hidden;
}

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

Using Angular to display asynchronous data with ngIf and observables

In cases where the data is not ready, I prefer to display a loader without sending multiple requests. To achieve this, I utilize the as operator for request reuse. <div class="loading-overlay" *ngIf="this.indicatorService.loadingIndicators[this?.indic ...

Is it feasible to trigger a selector element in Angular 2 upon clicking another element?

I want to trigger the Angular2 Material Datepicker's calendar popup by clicking on another element on the page. More specifically: <material-datepicker> </material-datepicker> should be triggered when a specific text is clicked: <p&g ...

Exploring the most effective strategies for creating a brand-new type in TypeScript?

In the execution environment I'm working with, there are several global constants that represent different directions: TOP = 1 TOP_RIGHT = 2 RIGHT = 3 BOTTOM_RIGHT = 4 BOTTOM = 5 BOTTOM_LEFT = 6 LEFT = 7 TOP_LEFT = 8 These constants are not just ran ...

What advantages could learning ReactJS first give me before diving into NextJS?

Just mastered TS and now faced with the decision of choosing a framework. I'm curious why it's recommended to learn ReactJS before NextJS. I've read countless articles advising this, but no one seems to delve into the reasons behind it. Ca ...

Implementing Limited Results in Redis FT.SEARCH with TypeScript

Snippet of code: client.ft.SEARCH('license-index-json',"@\\$\\" + ".reservedForApplicationName:GSTest",{ LIMIT: { from: 0, to: 1 } }) Error message: An error occurred when trying t ...

How can an Angular 2 component detect a change in the URL?

My Angular 2 component subscribes to a service based on the URL hash without calling any subcomponents. I am wondering if I should use Route or Location for this scenario, and how can I listen for and react to a pop state event? ...

Protractor enables horizontal scrolling for a Div element

My struggle to scroll to the right persists despite all attempts I experimented with various solutions, but none seem to work await browser.executeScript('arguments[0].scrollIntoView(true)',element.getWebElement()) The issue still remains unr ...

Tips for creating a responsive swiper slider in an Angular project

In my Angular project, I am using a swiper slider with 4 items in desktop view. However, I would like to display only 1 item in the mobile view. You can see the code at this link: https://stackblitz.com/edit/ngx-swiper-wrapper-demo-h9egdh?file=app/app.com ...

Failing unit test for ngrx effect with { dispatch: false } setting and action returned by the effect

Take a look at this code snippet: loadProducts$ = createEffect(() => this.actions$.pipe( ofType(requestLoadProducts), switchMap(action => this.service.load().pipe( map(data => loadProducts({products: data})) )) ) , { dispatch ...

Using TypeScript to pass a callback function to labelFormatter in the legend of a Highcharts chart

I am currently experimenting with integrating HighCharts into an Angular2 project using TypeScript. My goal is to customize the appearance of the legend text, adding an image next to it. I've found that HighCharts provides a labelFormatter property w ...

Steps to trigger pipe activation in Angular when the model is updated:1. Execute the

I have a unique filter pipe that allows me to filter an array of objects. This filter pipe has a dependency injection through a service. The service contains the model data filterService.data. Is there a way to activate this pipe in the template only when ...

How do I determine if a child component is in a dirty state within CanDeactivateGuard when dealing with multiple form tags?

Currently, I am utilizing a template driven form within my project. The parent component that I am working on is as follows: parent.component.html <tab> <form> <input></input> <button></button> </form ...

When we mention TypeScript and CDK, we are actually talking about the very foundation

As I was working on my current Stack constructor, I came across the Stack.formatArn() method. I started to wonder about the difference between using this.formatArn() and cdk.Stack.of(this).formatArn(). After all, shouldn't "this" refer to the stack it ...

GitHub Actions causing build failure in Angular project exclusively

I've encountered an issue where the GitHub Action workflow fails to compile an Angular project, even though it works fine on my local machine and that of my colleagues. It's worth noting that I'm using npm ci instead of npm install. The err ...

React Quill editor fails to render properly in React project

In the process of developing an application in Ionic React, I am in need of a rich text editor that can save data on Firestore. Despite initializing the editor as shown below and adding it to the homepage component, it is not rendering correctly although i ...

Proper method for typing the generics of DatePickerProps belonging to the DatePicker component in mui-x library

I have a component called CustomDatePicker which has been configured for localization as shown below: function CustomDatePicker(props: DatePickerProps<unknown> & React.RefAttributes<HTMLDivElement>) { return ( <StyledDatePicker ...

"Learn the process of distinguishing between a drop-down value and a selected value within a drop-down menu using angular2-multiselect

I need assistance with a requirement involving a multi-select drop-down menu where the values are in the format of "Code - Name". When an option is selected from the drop-down, only the "Code" should be displayed. I am currently using angular2-multiselec ...

How to implement a reusable module with distinct routes in Angular

In my current angular project, we have various menus labeled A, B, C, D, and E that all utilize the same module. Specifically, menus A, C, and E use the same component/module. My goal is to ensure that when I am on menu A and then click on menu C, the sa ...

Updating a label dynamically in Angular

QUESTION: Is there a way to dynamically change the text of a label based on a certain condition? Specifically, I want the label to be blank when I'm on a specific route in my App. CURRENT APPROACH: <RadSideDrawer allowEdgeSwipe=&quo ...

Error: The reference 'GetServerSideProps' is being incorrectly used as a type instead of a value. Perhaps you intended to use 'typeof GetServerSideProps' instead?

Index.tsx import Image from 'next/image' import Head from "next/head" import { sanityClient, urlFor } from "../sanity" import Link from 'next/link' import {Collection, address} from '../typings'; import ...