Skip to content
This repository has been archived by the owner on Apr 13, 2022. It is now read-only.

[IE11]: Checkbox state and ng-model binding not in sync on calling preventDefault inside click handler #17087

Open
Amrender-Singh opened this issue Oct 9, 2020 · 2 comments

Comments

@Amrender-Singh
Copy link

Amrender-Singh commented Oct 9, 2020

Description

Currently in our application we have a checkbox with a ng-model binding and a click handler attached to it. We want our checkbox to be checked only if certain business logic is met. To prevent the checkbox from getting checked, we call the event.preventDefault() method inside of our click handler attached to our checkbox element. Though the preventDefault() prevents the checkbox from being checked, but in IE11 it can be observed that the ng-model binding is updated, i.e binded variable has default value set to false, the value now updates to true, but the checkbox state remains unchanged. Also, this can be observed only when we click on the checkbox for the first time, after that on clicking on the checkbox the value remains unchanged if we call preventDefault() method.

🔬 Minimal Reproduction

Here, is the plunker for the issue described above:

http://plnkr.co/edit/FP34eXyPVZu5G9wN?preview

Note

It was observed that before version- 1.7x , the above mentioned issue could be observed in all the browsers. But for angular.js 1.7+ it can only be seen in IE11. Here is the plunker using version 1.6.0:

http://plnkr.co/edit/oKDonlG8XnKEGn8k?preview

Also, on looking into the source code. It was found that currently for input checkboxes listen to the change event for model updates. Which can be seen here:

element.on('change', listener);

It works fine in Chrome/firefox as the change event in these browser is triggered after the click event. So in case we call preventDefault() method in our click event handler the checkbox state is not changed. However in case of IE11 the change event is triggered before the click event.

@gkalpak
Copy link
Member

gkalpak commented Oct 10, 2020

Thx for reporting the issue, @Amrender-Singh. I am not sure this is something that would need to be fixed in AngularJS (AngularJS uses the change event - it is expected that cancelling the click event will not necessarily cancel the change event).

In any case, AngularJS is in LTS mode now and this issue does not satisfy the criteria for the issues we are providing fixes for. So, I'm afraid this is not going to be fixed.

If you find a solution or work-around, feel free to post it here for others that might be having the same issue.

@Amrender-Singh Amrender-Singh changed the title [IE11]: Checkbox state and ng-model binding not in sync on calling preventDefault inside click hanlder [IE11]: Checkbox state and ng-model binding not in sync on calling preventDefault inside click handler Oct 11, 2020
@Amrender-Singh
Copy link
Author

The workaround for this issue could be to call the $setViewValue method inside the change event listener of checkbox input inside setTimeout in case of IE only . so the updated checkboxInputType function implementation could be:

function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
  var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);

  var listener = function(ev) {
    if (isIE11) {
      setTimeout(function() {
        ctrl.$setViewValue(element[0].checked, ev && ev.type);
      });
    } else {
      ctrl.$setViewValue(element[0].checked, ev && ev.type);
    }
  };

  element.on('change', listener);

  ctrl.$render = function() {
    element[0].checked = ctrl.$viewValue;
  };

  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
  // it to a boolean.
  ctrl.$isEmpty = function(value) {
    return value === false;
  };

  ctrl.$formatters.push(function(value) {
    return equals(value, trueValue);
  });

  ctrl.$parsers.push(function(value) {
    return value ? trueValue : falseValue;
  });
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants