Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 3160

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 61k
Author
Asked: November 26, 20242024-11-26T12:08:07+00:00 2024-11-26T12:08:07+00:00

Custom/Reusable Toggle Component (with Angular Animations)

  • 61k

Had to create a toggle recently from scratch and, given the features that come with Angular, it was super easy and fast to do. Thought I'd share.

Workflow

  1. Create a starting toggle with two divs that layer on themselves using SCSS/CSS
  2. Add animation to the toggle using Angular Animations package
  3. Change the toggle background color, based on current toggle state
  4. Emit state to parent component

Jump ahead

  • Creating a Starting Toggle
  • Using Angular Animations Instead of CSS
    • Add BrowserAnimationsModule
    • Add an Animation Trigger to Template File
    • Animation State Behavior
  • Add Click Event
  • Full Code
    • Toggle SCSS File
    • Toggle Template File
    • Toggle Component File
    • Parent Template File
    • Parent Component File

Create a Starting Toggle

First, to drive the behaviour of the toggle, add a state property to the actual component:

// toggle.component.ts export class ToggleComponent implements OnInit {   toggleOn = false;   ... } 
Enter fullscreen mode Exit fullscreen mode

In the template, add a container div, an inner div (to act as the background color), and an inner-inner div to act as the actual toggle square:

<!--toggle.component.html--> <a class="toggle-container">   <div class="toggle-bg">     <div class="toggle"></div>     </div> </a> 
Enter fullscreen mode Exit fullscreen mode

To get a div to appear over another div (and stay within that behind div's boundaries), you'll want to make the give the background div's position: relative and the foreground div's position: absolute. Remember that absolute only works when you've added a x and y axis keys like this:

@import '~./src/app/scss/colors.scss';  .toggle-bg {     display: inline-block;     height: 1rem;     width: 2rem;     background-color: $accent-color;     border-radius: 3px;     position: relative;    .toggle {         width: 1rem;         display: inline-block;         background-color: white;         position: absolute;         left: 0.01rem;         top: 0;         bottom: 0;         margin: 0.1rem;         border-radius: 3px;         box-shadow: 2px 2px 12px #00000050;     } }  .toggle-on {   background-color: $primary-color; } 
Enter fullscreen mode Exit fullscreen mode

Notice that I only referred to a state change of color (no animations). We'll add this later.


Using Angular Animations Instead of CSS

I like using Angular Animations since (like most of their features) they're state-driven instead of just being event driven. If we just track a click event, there might be a case where the click order gets out of sync and 'on' might not mean 'on' anymore.

Add BrowserAnimationsModule

In you app.module.ts file add

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  @NgModule({     declarations: [...],     imports: [     ...     BrowserAnimationsModule   ],     providers: [...],     bootstrap: [AppComponent] }) 
Enter fullscreen mode Exit fullscreen mode

Add an Animation Trigger to Template File

In your toggle.component.html file, add a trigger by adding [@] to the element you want to animate (in this case, the toggle that moves). This is followed by a ternary operator that takes the state property we created earlier (toggleOn = false;) and provides an 'if/else' outcome based on that property's condition:

<!--toggle.component.html--> <a class="toggle-container">   <div class="toggle-bg">         <div        [@toggleTrigger]="toggleOn ? 'on' : 'off'"        class="toggle">     </div>   </div> </a> 
Enter fullscreen mode Exit fullscreen mode

This means: if toggleOn is true, then the state of this animation is on, else the state of this animation is off.

Animation State Behavior

Now we apply the behaviours that happen when the toggle is 'on' or 'off' in the actual component.

  • First we import the animation functions from the @angular/animations package (kind of annoying but whatever)
  • Then we add the animation trigger, states, and behaviour (with styles) to the actual component metadata
import { Component, OnInit } from '@angular/core'; import { animate, state, style, transition, trigger } from '@angular/animations';  @Component({     selector: 'app-toggle',     templateUrl: './toggle.component.html',     styleUrls: ['./toggle.component.scss'],     animations: [     // First we add the trigger, which we added to the element in square brackets in the template         trigger('toggleTrigger', [     // We define the 'off' state with a style -- translateX(0%), which does nothing           state('off', style({ transform: 'translateX(0%)' })),     // We define the 'on' state with a style -- move right (on x-axis) by 70%           state('on', style({ transform: 'translateX(70%)' })),     // We define a transition of on to off (and vice versa) using `<=>`           transition('on <=> off', [     // We add the time (in milliseconds) and style of movement with `animate()`             animate('120ms ease-in-out')           ])       ])   ]}) 
Enter fullscreen mode Exit fullscreen mode


Add Click Event

Because we want to be able to track if the state is either 'on' or 'off' in the future, we won't want to use a simple (click)=”toggleOn = !toggleOn”. Instead, we'll create a new function called toggleClick() which will do two things:

  1. Based on the current state of the toggle, be able to switch it from on to off and vice versa
  2. Emit the actual state with a string to any parent component using it

To do this, we want to import the @Output() property and the EventEmitter method to the component from @angular/core

// toggle.component.ts import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; 
Enter fullscreen mode Exit fullscreen mode

We add this to the component class, and name the EventEmitter so that we have something to emit values in the first place. We also want to add @Input() property to the toggleOn property so that a parent can access it:

export class ToggleComponent implements OnInit {   @Input() toggleOn = false;   @Output() toggledTo = new EventEmitter(); ... } 
Enter fullscreen mode Exit fullscreen mode

Then we add a conditional function which will trigger the toggling of on and off, and send its states to the parent component:

export class ToggleComponent implements OnInit {   @Input() toggleOn = false;   @Output() toggledTo = new EventEmitter();    constructor() { }    ngOnInit(): void {  }  // We will have the `toggleTo` EventEmitter emit a string  toggleClick(): any {       if (this.toggleOn) {           this.toggleOn = false;           this.toggledTo.emit('off');       } else {             this.toggleOn = true;             this.toggledTo.emit('on');         }     } } 
Enter fullscreen mode Exit fullscreen mode

Also, since the state is now rigidly defined, we can add a conditional [ngClass] to the toggle-bg div, so that it knows to add the class 'toggle-on' when the state is toggleOn and consequently change the background color (as in the SCSS file).

<a    class="toggle-container"    (click)="toggleClick()">      <div     [ngClass]="toggleOn ? 'toggle-bg toggle-on' : 'toggle-bg'">         <div [@toggleTrigger]="toggleOn ? 'on' : 'off' " class="toggle">     </div>     <div> </a> 
Enter fullscreen mode Exit fullscreen mode

Again, the boys at Angular love ternary operators — which is great. So with [ngClass], we're saying that IF the state is toggleOn (true), then use the classes toggle-bg toggle-on ELSE just use toggle-bg.

Now you can add it to a parent component and create a function within that parent which will catch the emitted value:

<!--parent.component.html--> <app-toggle (toggleTo)="onToggleClick($event)"></app-toggle> 
Enter fullscreen mode Exit fullscreen mode

// parent.component.ts export class ParentComponent implements OnInit { ...    onToggleClick(value): void {       console.log(value);   // will print 'on' or 'off' depending on state     } 
Enter fullscreen mode Exit fullscreen mode


Full Code

Toggle SCSS File

toggle.component.scss

@import '~./src/app/scss/colors.scss';  .toggle-bg {     display: inline-block;     height: 1rem;     width: 2rem;     background-color: $accent-color;     border-radius: 3px;     position: relative;    .toggle {         width: 1rem;         display: inline-block;         background-color: white;         position: absolute;         left: 0.01rem;         top: 0;         bottom: 0;         margin: 0.1rem;         border-radius: 3px;         box-shadow: 2px 2px 12px #00000050;     } }  .toggle-on {   background-color: $primary-color; } 
Enter fullscreen mode Exit fullscreen mode

Toggle Template File

toggle.component.html

<a    class="toggle-container"    (click)="toggleClick()">     <div     [ngClass]="toggleOn ? 'toggle-bg toggle-on' : 'toggle-bg'">         <div [@toggleTrigger]="toggleOn ? 'on' : 'off' " class="toggle"></div>     </div> </a> 
Enter fullscreen mode Exit fullscreen mode

Toggle Component File

toggle.component.ts

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { animate, state, style, transition, trigger } from '@angular/animations';  @Component({     selector: 'app-toggle',     templateUrl: './toggle.component.html',     styleUrls: ['./toggle.component.scss'],     animations: [         trigger('toggleTrigger', [             state('off', style({ transform: 'translateX(0%)' })),             state('on', style({ transform: 'translateX(70%)' })),             transition('on <=> off', [                 animate('120ms ease-in-out')             ])         ])   ]})  export class ToggleComponent implements OnInit {   @Input() toggleOn = false;   @Output() toggledTo = new EventEmitter();    constructor() { }    ngOnInit(): void {  }    toggleClick(): any {       if (this.toggleOn) {           this.toggleOn = false;           this.toggledTo.emit('off');       } else {           this.toggleOn = true;           this.toggledTo.emit('on');       }   }} 
Enter fullscreen mode Exit fullscreen mode

Parent Template File

parent.component.html

<app-toggle (toggledTo)="onEditorToggle($event)"></app-toggle>  
Enter fullscreen mode Exit fullscreen mode

Parent Component File

parent.component.ts

export class ParentComponent implements OnInit {      constructor() { }      ngOnInit(): void {  }    onEditorToggle(value): void {     console.log(value);     } } 
Enter fullscreen mode Exit fullscreen mode

angularjavascripttypescriptwebdev
  • 0 0 Answers
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    Insights into Forms in Flask

    • 0 Answers
  • Author

    Kick Start Your Next Project With Holo Theme

    • 0 Answers
  • Author

    Refactoring for Efficiency: Tackling Performance Issues in Data-Heavy Pages

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.