The synchronization issue between ng-class and animation

I'm experiencing a strange issue with ng-class and suspect that it may be related to a race condition.

Here is the example on Plunker: example

Below is the relevant JavaScript code:

    self.slideLeft = function() {
      if (self.end_index < self.list_of_stuff.length) {
          self.direction = 'left';

          debugger;
          self.start_index = self.start_index + 4;
          self.end_index = self.end_index +  4;
          self.display_list = self.list_of_stuff.slice(self.start_index, self.end_index);            
      }

    }

    self.slideRight = function() {
      if (self.start_index > 0) {
          self.direction = 'right';
          debugger;

          self.start_index = self.start_index - 4;
          self.end_index = self.end_index -  4;
          self.display_list = self.list_of_stuff.slice(self.start_index, self.end_index);            
      }
    }

Here is the relevant HTML:

  <div class="stuff-wrapper">
    <div class="stuff" 
         ng-class="bCtrl.directionClass()" 
         ng-repeat="stuff in bCtrl.display_list">
      {{stuff}}
    </div>
  </div>

Animation:

.left.ng-enter,
.left.ng-leave {
    -webkit-transition: all 1s ease-in-out;

}

.left.ng-enter {
    transition-delay: 0.7s;
    opacity: 0;
    left: 10%;
}
.left.ng-enter-active {
    opacity: 1;
    left: 0;
}

.left.ng-leave {
    opacity: 1;
    left: -10%;
}
.left.ng-leave-active {
    left: -20%;
    opacity: 0;
}

This app simply slides a list of numbers left and right. When left button is pressed, numbers slide left. When right button is pressed, numbers slide right. However, when there is a change in direction, initially the numbers slide in the wrong direction before correcting themselves.

I suspect this is due to a race condition. It seems that ng-class does not get applied immediately after changing the direction self.direction during debugging.

Quite peculiar. Any suggestions on how to resolve this?

Answer №1

Referencing the response provided in this () inquiry:

The solution requires adjusting the $scope.elements after the CSS class has been updated in the DOM. It is essential to postpone the DOM manipulation for a single digest loop. This can be achieved using the $timeout service (refer to this response for more insights on AngularJS $evalAsync vs $timeout):

When you remove the elements within the same digest loop as the CSS class modifications, the CSS doesn't update properly and the elements are simply eradicated.

The digest loop will encompass your entire ng-click function, as all angular built-in directives wrap the code inside a $scope.$apply call.

To elaborate:

$scope.$apply() accepts a function or an Angular expression string, executes it, and then invokes $scope.$digest() to update any bindings or watchers.

For further details, refer to this link ().

The solution to your issue involves wrapping the data removal from your array in a $timeout block. This action will postpone the DOM manipulation for one digest loop and segregate the class change from the data removal:

self.slideLeft = function() {
          if (self.end_index < self.list_of_stuff.length) {
              self.direction = 'left';

              self.start_index = self.start_index + 4;
              self.end_index = self.end_index +  4;
              $timeout(function(){
                self.display_list = self.list_of_stuff.slice(self.start_index, self.end_index);            
              });
          }

        }

        self.slideRight = function() {
          if (self.start_index > 0) {
              self.direction = 'right';

              self.start_index = self.start_index - 4;
              self.end_index = self.end_index -  4;
              $timeout(function(){
                self.display_list = self.list_of_stuff.slice(self.start_index, self.end_index);            
              });
            }
        }

Here is a functional plunker for reference: http://plnkr.co/edit/30wJhL?p=preview

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

Data is not appearing when using Node.js with mongoose and the populate() method

I am facing an issue while trying to display data from a database. Even though I have integrated 3 different schemas into one, the combined data is not being displayed as expected. I have attached all three schemas for reference. While async-await along w ...

I am experiencing an issue where tapping on the Status Bar in MobileSafari is not functioning correctly on a specific

I am struggling to troubleshoot this problem with no success so far. The HTML5 JavaScript library I'm developing has a test page that can display a large amount of output by piping console.log and exceptions into the DOM for easy inspection on mobile ...

Is there a way to simulate a click event within a Jasmine unit test specifically for an Angular Directive?

During the implementation of my directive's link function: $document.on('click.sortColumnList', function () { viewToggleController.closeSortColumnList(); scope.$apply(); }); While creating my unit test using Jasmine: describe(&apo ...

The component "SafeAreaViewRN" could not be located within the UIManager

Upon attempting to open a bundle on my Android device, I encountered the following error message: A warning was displayed stating that the app was accessing a hidden field in android's view accessibility delegate. Additionally, an Invariant Violati ...

Optimizing Page Load Time in AngularJS with the ng-include Directive

My current challenge involves populating a page in stages. There are multiple categories with varying numbers of items, and my code structure resembles the following (warning: slightly jumbled). $scope.getItems = function(key) { $http.get('get-item ...

The chaotic world of Android WebKit versions 2.x and 3.x

I have been working on an Android app and my goal is to make it compatible with Android versions 2.2 and above. Currently, due to issues with the WebView control, I am restricted to targeting Android 4.0 and higher. The app primarily uses HTML, CSS, Java ...

What is the purpose of using "recaptcha_get_html" function to echo?

Hello everyone. I've been struggling to incorporate Google's reCAPTCHA into my project and I keep encountering an error when trying to use the recaptcha_get_html function. It keeps showing up as undefined and despite searching high and low, I can ...

tips for moving a button 2 pixels up or down in position

How can I adjust the position of my button by a specific number of pixels up or down from where it currently is? Can you provide guidance on how to find the current location? Thank you in advance. ...

Determine the amount of unused vertical space within a block of text

Having applied CSS to a span element: font-height = 120px; height = 120px; line-height = 120px; The text inside the span does not completely fill the height of 120px. Is there a method to determine the offset of the text from the top and bottom boundar ...

Having trouble getting the map function to work in ReactJs while using Next.js?

Hey there, I am diving into ReactJS with the "Nextjs" framework and working on fetching data using async functions. However, I am facing an issue where I am unable to fetch data using the map function. The console.log is displaying a message saying "item ...

Height Miscalculation: Chrome and FF encounter window dimension

There is a large application with numerous pages. When I use the console to execute console.log($(window).height()) on any page within the application, it returns the expected result: the height of the window, not the document. For instance: $(window).he ...

Tips for implementing varying styles depending on the number of columns in a table

I am working with multiple tables that share similarities, but differ in the number of columns each table has. I am looking to create a styling rule where depending on the number of columns, the width of each column will be set accordingly. For example, if ...

Creating an Active Link in Bootstrap 5.0 (Beta 3) Navbar Using JavaScript

I am currently working with Bootstrap 5 (Beta 3 - no JQuery) on a static website, and I am facing the challenge of making a navbar link appear active. I prefer to achieve this using JavaScript instead of creating a separate navbar for each page. For instan ...

Ways to confirm my CSS modifications in Chrome Developer Tools

I find myself tweaking the CSS of various elements using dev tools. After making multiple changes, I often lose track of where I have applied new styles to the elements. Is there a way to easily compare the current styles with the original styles on the ...

Substitute link with asynchronous JavaScript and XML

I need to enable/disable user accounts by clicking on an anchor. The list of users is created dynamically using a loop. Here's an example of an anchor tag: <a href="http://www.example.com/users/deactivate/44" class="btn btn-success" title="Deactiv ...

Dealing with an empty req.body parameter in a NodeJS function for a Rest API using ExpressJs and sequelize

Looking for assistance with integrating ExpressJS and sequelize. I have a main function (fullaccount.js) that needs to invoke two functions ("accoun.js" and "people.js") receiving data in "fullaccount.js" for processing. However, while req.body is ready in ...

When clicking on a dropdown option, the OnClick event does not seem

When selecting an option from the dropdown, it should retrieve a value from the database and display it in a text field. I implemented a click function which worked in Firefox but not in Google Chrome. HTML: <select id="classi" name="classi"> & ...

Tips for effectively using the question mark as a separator in a webservice URL

In my nodejs / express project, I am attempting to create a webservice where I separate the URL from parameters using '?' and use '&' as parameter separators. When using this method, it works perfectly fine: app.get("/tableref/:event/ ...

displaying a video within an iframe without occupying the entire screen

After successfully implementing a fullscreen video background using the "video" tag with a video hosted on my own server, I decided to switch it out for a Vimeo video. However, after making the necessary code and CSS changes, the video now appears like thi ...

The database does not get updated by an Ajax request without a page refresh

I'm currently in the process of developing a dashboard system and I've created a ToDo list for it. The main functionality of the system is to allow users to add, delete, and mark tasks as finished or unfinished. I am using codeIgniter for this p ...