Leveraging ng-class for selectively applying CSS3 animations based on conditions

When specific conditions are met in my controller, I apply two CSS3 animations to the DOM using ng-class. The animations (shake Y & shake X) are added based on certain criteria being satisfied. Here is a snippet of the relevant JavaScript code:

$scope.submitAnswer = function($index) {

    if ($index == current) {
        console.log('correct!');
        $scope.shaken = 'shakeY';
    }
    else {
        console.log('incorrect!');
        $scope.shaken = 'shakeX';
    }
}

Here's the corresponding HTML:

    <div 
        id="philosopher" 
        ng-class="shaken"
        ng-click="submitAnswer($index);" 
        ng-repeat="philosopher in philosophers">
        <img ng-src="images/{{philosopher.signifier}}.png" height="142px" width="auto" />
        <h2>{{philosopher.name}}</h2>
    </div>

Although this setup works as intended, I've encountered an issue where I can't keep reapplying the same animation class consecutively - I need to switch between triggering the if statement and the else statement.

I came up with a custom directive using ngAnimate to repeatedly trigger the animation. However, I'm struggling to implement separate animations based on the outcome of the if-else statement. Here's an example of one of the directives I tried:

app.directive('shake', function($animate) {
    return {
        restrict: 'A',
        scope: false,
        link: function(scope, element, attrs) {

            element.bind('click', function() {

                $animate.addClass(element, 'shakeX', function() {
                    $animate.removeClass(element, 'shakeX');
                });

            });
        }
    };
});

How can I continuously reapply shakeX and shakeY to ng-class or only use my directive based on the result of the if-else statement?

EDIT

I was able to resolve the issue! After some trial and error, I found that implementing a timeout function within the if statement worked perfectly. Although it may not be conventional to use functions inside if statements, this approach got the desired animation effect. Here's how I achieved it:

    if ($index == current) {
        console.log('correct!');
        $timeout(function() {
            $scope.shaken = 'shakeY'
        })
    }
    else {
        console.log('incorrect!');
        $timeout(function() {
            $scope.shaken = 'shakeX'
        })
    }

Answer №1

To achieve your desired outcome, there is no need for a directive. The issue arises when you assign the same value to a scope property because the watcher for that property will not trigger if the value remains unchanged. To work around this, you should first change the value of the scope property to a different or empty value, and then utilize a $timeout to switch it back to the original value.

Here's an example:

DEMO

HTML

<div ng-class="shake" ng-click="shakeX()">Shake X</div>
<div ng-class="shake" ng-click="shakeY()">Shake Y</div>

JAVASCRIPT

$scope.shakeX = function() {
  $scope.shake = '';
  $timeout(function() {
    $scope.shake = 'shakeX';
  })
};

$scope.shakeY = function() {
  $scope.shake = '';
  $timeout(function() {
    $scope.shake = 'shakeY';
  })
};

Answer №2

Changing Classes Directly

Based on our previous discussion in the comments, it seems like using a timeout during the animation is the most effective approach. Simply modify this snippet:

$animate.addClass(element, 'shakeX', function() {
    $animate.removeClass(element, 'shakeX');
});

to:

$animate.addClass(element, 'shakeX', function() {
    $timeout(function() {
        $animate.removeClass(element, 'shakeX');
    }, 420);
});

Remember to include the $timeout dependency.

In short, the goal is to remove the class once the CSS animations have finished so that it can be applied again when needed.


Using Controller Scope Variable

If you prefer sticking with your original approach from the controller, you can try something like this:

if ($index == current) {
    console.log('correct!');
    $scope.shaken = 'shakeY';
}
else {
    console.log('incorrect!');
    $scope.shaken = 'shakeX';
}

$timeout(function() {
    $scope.shaken = false;
}, 420);

This method resets the scope variable after the animation without specific concern for the class name.


$watching Scope Variable with Linker Function

To handle everything within the directive's linker function, consider implementing the following code snippet:

scope.$watch('shaken', function(newValue, oldValue) {

    if (newValue != 'shakeX' && newValue != 'shakeY')
        return; // just to be safe

    $animate.addClass(element, newValue, function() {
        $timeout(function() {
            $animate.removeClass(element, newValue);
        }, 420);
    });
});

The code above observes changes in the shaken variable and applies necessary updates accordingly.

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

What is the proper type declaration for incoming data from the backend in my TypeScript code when using axios?

In the TypeScript code snippet provided, the type for 'e' (used in the function for form submission) has been figured out. However, a question arises if this type declaration is correct. Additionally, in the catch block, the type "any" is used fo ...

What is the process for creating an index signature for a type alias representing a Map in Typescript?

Suppose I have a custom type for a Map as follows: type MyCustomMap = Map<string, number>; Is there any way to add an index signature to this type so that I can set key-value pairs after initializing it? I have been able to achieve this with types ...

Sorting data in AngularJS using the OrderBy filter in ascending

I am using ng-repeat in my code: <label ng-repeat="atp in Keywords | unique:'atp'"> {{atp}} </label> The values in atp are as follows: client animal zoo boat I want the final output to be: animal boat client zoo Thank you for ...

Increase the Step Size of an HTML Number Input by Holding Down the Time

Is there a way to implement increasing increment/step size for number inputs in HTML based on how long the user holds the stepper arrows? For instance, starting at step size=1 and gradually ramping up to larger increments like 5, 10, 20, etc. after holdin ...

Prevent content from occupying unnecessary space below a sticky div

When the "link" on the sticky header is clicked in this scenario, how can I ensure that the linked content item (#mypara) appears below the sticky div rather than directly underneath it where it may be hidden? $(document).ready(function() { $(window ...

JavaScript array loading failed for the C# web service

I am encountering an issue with a JavaScript object in my application that contains an array object, which is a collection of objects with two properties (Name, Value) on the server-side. Despite my efforts, when the code reaches the C# web service, the C ...

Issue with data binding in the header title when using AngularJS within the Ionic framework

I am currently utilizing a framework called "Ionic" that is based on AngularJS (http://ionicframework.com/). Although it may seem straightforward, I am encountering some difficulties with its functionality. Within one of my views, the following code snip ...

Why does babel-node encounter a "module not found" error when the ".js" extension is not included?

Why is babel-node not importing without the ".js" extension? I have "type": "module" in my package.json import example from "./src/example.js"; works fine import example from "./src/example"; does not work --es-module-specifier-resolution=node only works ...

The checkbox must be checked for the conditional form to appear, experiencing a Safari bug in version 12.2. No issues found in Chrome and Firefox browsers

My form includes a billing address section with a checkbox that automatically sets the shipping address to match the billing address. If the user unchecks the checkbox, another form will appear below for entering a different shipping address. The Checkbox ...

Combining duplicate key-value pairs in a JSON object into an array using JavaScript

Is it possible to merge value objects with the same key but different values? For example, in this case, "field_template_id": 2 appears twice with different values. This is the original JSON data: { "id": "c2dec94f", "data": [ { "field_temp ...

Creating an element in JavaScript with a designated ID is a

I'm working on creating a JavaScript array that holds 3 elements: var employees = [ {"firstName":"John", "lastName":"Doe"}, {"firstName":"Anna", "lastName":"Smith"}, {"firstName":"Peter", "lastName":"Jones"} ] To iter ...

Creating dynamic web pages with jQuery is a simple and effective

I am currently using jQuery to create HTML elements with specific classes and then append them together. However, the code I have written is not adding the generated HTML to the container as expected. There are no errors being produced but the HTML is not ...

Is it simple to customize the color of the close button in Bootstrap 5?

Bootstrap's v5 release brings updated styling to various components, including the close button. In previous versions, the close button had an "x" that could be easily styled with text properties, like inheriting color from its parent. However, in v5, ...

Modifying a single route among several nested routes with specific names

My template includes various named, nested views: Template 1: <body> <div ui-view></div> </body> Template 2: <header></header> <div ui-view="left"></div> <div ui-view="canva ...

How can I use a JavaScript or jQuery function to choose a specific audio track that is currently playing locally?

Currently, I have developed a music app that features local mp3 files triggered by clicking on divs which are linked to the audio using an onClick function with the play() method. Additionally, there is a scrolling screen that displays the song's arti ...

Reactjs rendering problem related to webpack

Greetings! I am new to using react js and decided to create a quiz application. However, I encountered an error when the render function was called. Below is my webpack.config file: module.exports = { entry: { app: './src/index.js' }, ...

Gain a comprehensive understanding of the JavaScript syntax utilized throughout the code

I stumbled upon this JavaScript code that enables asynchronous file uploads, but there are certain parts of it that I'm struggling to grasp. Any insights or explanations would be greatly appreciated - many thanks in advance. // Utilizing Ajax for Fil ...

What is the best way to retrieve a specific value from a JSON file using a numerical identifier?

Imagine a scenario where there is a JSON file structured like this: { "data": [ { "id": "1", "name": "name1" }, { "id": "2", "name": "name2" } ] } If you know the ...

React application triggers `OnKeyDown` event just once

Hey there! I'm diving into the world of web development and could use some help. My current challenge involves manipulating input data based on key combinations like ctr + ArrowUp (increase) and ctr + ArrowDown (decrease). The dynamic part should be h ...

Determine if a specific value is present in an array of objects using AngularJS

var arr = [ { id:1}, {id:2} ]; var obj = {id:1}; var result = arr.indexOf(obj.id) == -1; console.log(result); I am trying to determine if obj.id exists in the array arr[]. Please note: arr[] is an array of objects ...