What is causing the race condition in the order of AngularJS directive listeners?

I am currently facing an issue with a custom directive that is listening to change events on input elements using jQuery's delegate function. The problem arises in Chrome where the listener fires before the ng-models update, resulting in stale data within my directive. Interestingly, it seems to work fine in Firefox. Could this be related to the order of listeners being attached? Here is an example:

The HTML:

<div my:change="myChange()">
    <input type="checkbox" ng:change="ngChange()" ng:model="foo" ng:true-value="foo" ng:false-value="bar" />
</div>

And the JS:

app.controller('MainCtrl', function($scope) {

  $scope.foo = 'foo'; // Source
  $scope.bar = 'foo'  // w/o $timeout
  $scope.bar2 = 'foo' // with $timout

  $scope.ngChange = function() {

    console.log('ngChange');
  }

})
.directive('myChange', ['$timeout', function($timeout) {
  return {
    link: function($scope, $element, $attrs) {

     $element.delegate('input', 'change', function(event) {

       console.log('myChange')

       // A value was changed, let's update the value from the model.
       $timeout(function() {
         $scope.bar2 = $scope.foo;
       })

       $scope.bar = $scope.foo;
     })
    }
  }

}]);

When the checkbox is checked $scope.foo should be updated. the ngChange gets called first in FF, second in Chrome, where as myChange gets called first Chrome and second in FF.

Adding the $timeout call makes it work as expected ($scope.foo has the value I expect), but that feels like a major hack.

Working plunkr of code above: http://plnkr.co/edit/Y1TWGKlkimS3H5Lqaisw

Answer №1

Have you considered making the change from $element to $($element)? Take a look at the code snippet below for more clarity...

app.controller('MainCtrl', function($scope) {

  $scope.foo = 'foo'; // Original
  $scope.bar = 'foo'  // without using $timeout
  $scope.bar2 = 'foo' // with $timout

  $scope.ngChange = function() {

    console.log('ngChange');
  }

})
.directive('myChange', ['$timeout', function($timeout) {
  return {
    link: function($scope, $element, $attrs) {

     $($element).delegate('input', 'change', function(event) {

       console.log('myChange')

       // A value has been changed, let's update it in the model.
       $timeout(function() {
         $scope.bar2 = $scope.foo;
       })

       $scope.bar = $scope.foo;
     })
    }
  }

}]);

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

Issue with large date changes causing MUI DatePicker to freeze

The MUI DatePicker, whether from Labs or X, was functioning perfectly. However, I am now facing an issue where it hangs when trying to change the date by ten years. It appears that the code gets stuck in an endless loop, yet there are no errors displayed i ...

Ways to incorporate services into functions within Angularjs

I'm struggling to grasp the concept of dependency injection in AngularJS. Currently, I am attempting to inject $interpolate and $eval into my controller. However, after consulting the documentation, I realized that my lack of foundational knowledge i ...

Guide on creating a custom type for an object utilizing an enum framework

Enumerating my shortcuts: export enum Hotkey { MARK_IN = 'markIn', MARK_OUT = 'markOut', GO_TO_MARK_IN = 'goToMarkIn', GO_TO_MARK_OUT = 'goToMarkOut' } I am now looking to define a type for a JSON ob ...

There seems to be an error: Unable to retrieve the value of 'socialsharing' from an undefined property

Creating an app on ionic and encountering the following error: TypeError: Cannot read property 'socialsharing' of undefined Please review my code for any mistakes. I am trying to develop a simple image sharing app, but I keep getting an error ...

Creating a Map in TypeScript from an Array

I have a series of TypeScript objects structured like this: interface MyObject { id: string, position: number } My goal is to transform this array into a map format where it shows the relationship between id and position, as needed for a future JSON ...

Is there a way to ensure that the elements created by the select form are only generated once?

I have a JavaScript function that dynamically creates paragraph and input elements based on user selection in HTML. However, I am looking to optimize the code so that each element is only created once. Snippet of JavaScript code: function comFunction(sel ...

Using AngularJS with ckEditor for managing multiple instances

My upcoming app will feature drag and drop functionality, as well as the ability to drop a CKEditor into it. I am facing an issue where all instances of the CKEditor created have the same "ng-model". Is there a way to create new instances with unique mode ...

The smooth scrolling feature fails to function properly in Lenis when clicking on links with specified IDs

Is there a reason why the scroll-behavior: smooth property doesn't function properly when Lenis library for smooth scrolling is included? It seems to work fine when the Lenis code is commented out, but once it's added back in, the scrolling isn&a ...

Setting up express with mongodb - A step-by-step guide

Currently exploring the world of Express App, I am attempting to configure mongodb using express and node.js. Facing a few issues in this process and seeking assistance. I have included directory references for better understanding. 1- The variable config ...

javascript unable to delete cookie

After conducting extensive research across various articles and links on deleting cookies using JavaScript, I have encountered an issue where the JavaScript code does not seem to be functioning as expected. The code I utilized for setting cookie values usi ...

Issue with combining md-grid-tile and md-button in Angular Material not functioning as expected

I've been trying to make a md-grid-list with md-grid-tiles into clickable links by wrapping them in an anchor tag or an md-button, but so far I haven't had any success. The element seems to disappear when I try this method. If anyone has any sug ...

From jQuery to HTML to PHP, then back to HTML from PHP through jQuery

Hey, I have a code snippet that I'm working on: <html> <head> <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script> <script type="text/javascript"> function get() { $.post(' ...

Tips for handling TypeError when testing formgroups in Angular unit tests---How to address TypeError

While attempting to conduct unit testing on my form fields in Angular, I encountered an issue with Karma stating that my property is undefined. When I logged the formGroup, it returned as undefined. However, upon logging my component, all parameters were r ...

How to Build a Custom Toolbar with Left and Right Aligned Elements using React.js and Material UI

Struggling with updating the toolbar on my website. Wanting the site name and logo on the left side, while login/sign-up buttons fixed to the right. Logo and title are in place, but can't get buttons to stay on right margin. Here's the code: func ...

Troubleshooting the issue of not successfully retrieving and sending values from form checkboxes in jQuery to $_POST variable

I am facing an issue with checkboxes that have identical names and use square brackets to create an array. <label> <input type="checkbox" value="Tlocrt objekta" name="dokument[]" > Tlocrt objekta </input> </label> ...

yo projectname Angular Command

Every time I run this command, I encounter a new error. It seems like as soon as I fix one module issue, another pops up. For instance, I recently encountered an error with the 'shelljs' module. The specific error message is as follows: Error: ...

Extract the chosen option from a dropdown menu, and then transfer it to another dropdown menu with a new corresponding value

Below is a select box I currently have: <td align="center"> <select id="selectW" name="type" onChange="this.form.submit()"> <option value="select...">select</option> <option value=" ...

The type 'void | Observable<User>' does not include the property 'subscribe'. Error code: ts(2339)

authenticate() { this.auth.authenticate(this.username, this.password).subscribe((_: any) => { this.router.navigateByUrl('dashboard', {replaceUrl: true}); }); } I'm puzzled by this error message, I've tried a few solu ...

When node.js v6.11.2 is installed on Windows 7, it does not include the correct npm version

When trying to install node.js v6.11.2 on my Windows 7 computer, I am encountering an issue where it is installing the incorrect version of npm alongside it. Even after downloading the installer directly from node.js' website which claims that 6.11.2 ...

Converting an array key into a string representation by compulsion

I need help maintaining the order of an array that has mixed key types. Most of the keys are represented by strings, but if a number is entered as a key, it moves to the front of the array. How can I ensure that a key which is a number remains as a string ...