Skip to content
This repository has been archived by the owner on Sep 8, 2020. It is now read-only.

Make all $apply calls safe #187

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 19 additions & 13 deletions src/mask.js
Expand Up @@ -49,7 +49,7 @@ angular.module('ui.mask', [])
return tempOptions;
}];
})
.directive('uiMask', ['uiMask.Config', function(maskConfig) {
.directive('uiMask', ['uiMask.Config', '$timeout', function(maskConfig, $timeout) {
function isFocused (elem) {
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
}
Expand Down Expand Up @@ -444,12 +444,14 @@ angular.module('ui.mask', [])
if (!isValid || value.length === 0) {
valueMasked = '';
iElement.val('');
scope.$apply(function() {
//only $setViewValue when not $pristine to avoid changing $pristine state.
if (!controller.$pristine) {
controller.$setViewValue('');
}
});
$timeout(function() {
scope.$apply(function() {
//only $setViewValue when not $pristine to avoid changing $pristine state.
if (!controller.$pristine) {
controller.$setViewValue('');
}
});
}, null, false);
}
}
//Check for different value and trigger change.
Expand Down Expand Up @@ -597,9 +599,11 @@ angular.module('ui.mask', [])
iElement.val(maskPlaceholder);
// This shouldn't be needed but for some reason after aggressive backspacing the controller $viewValue is incorrect.
// This keeps the $viewValue updated and correct.
scope.$apply(function () {
controller.$setViewValue(''); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
});
$timeout(function() {
scope.$apply(function () {
controller.$setViewValue(''); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
});
}, null, false);
setCaretPosition(this, caretPosOld);
return;
}
Expand Down Expand Up @@ -640,9 +644,11 @@ angular.module('ui.mask', [])
//we need this check. What could happen if you don't have it is that you'll set the model value without the user
//actually doing anything. Meaning, things like pristine and touched will be set.
if (valAltered) {
scope.$apply(function () {
controller.$setViewValue(valMasked); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
});
$timeout(function() {
scope.$apply(function () {
controller.$setViewValue(valMasked); // $setViewValue should be run in angular context, otherwise the changes will be invisible to angular and user code.
});
}, null, false);
}

// Caret Repositioning
Expand Down
6 changes: 6 additions & 0 deletions test/maskSpec.js
Expand Up @@ -233,6 +233,7 @@ describe("uiMask", function () {
input.triggerHandler("input");
expect(input.data("$ngModelController").$error.required).toBe(true);
input.val("(abc123_) _ _").triggerHandler("input");
timeout.flush();
expect(scope.x).toBe("ab1");
expect(input.data("$ngModelController").$error.required).toBeUndefined();
});
Expand Down Expand Up @@ -373,14 +374,17 @@ describe("uiMask", function () {

input.val("aa___").triggerHandler("input");
input.triggerHandler("blur");
timeout.flush();
expect(input.val()).toBe("aa_");

input.val("99a___").triggerHandler("input");
input.triggerHandler("blur");
timeout.flush();
expect(input.val()).toBe("99_");

input.val("992___").triggerHandler("input");
input.triggerHandler("blur");
timeout.flush();
expect(input.val()).toBe("992");
});

Expand Down Expand Up @@ -642,6 +646,7 @@ describe("uiMask", function () {
scope.$apply("mask = '@193'");
input.val("f123____").triggerHandler("input");
input.triggerHandler("blur");
timeout.flush();
expect(input.val()).toBe("f123");
});

Expand All @@ -659,6 +664,7 @@ describe("uiMask", function () {
scope.$apply("mask = '@193Ab'");
input.val("f123cCCc").triggerHandler("input");
input.triggerHandler("blur");
timeout.flush();
expect(input.val()).toBe("f123Cc");
});

Expand Down