scope.$watch not firing on variable change - javascript

I have the following snippet of code below. The problem I'm having is that whenever the value of modal.isOpen is set to true, the $watch statement does not fire. I'm trying to avoid using scope.$apply. What am I doing wrong here...
Inside Link function in an Angular directive:
link: function (scope, elem, attrs) {
scope.$watch('modal.isOpen', function(newValue, oldValue) {
if (newValue)
console.log("This does not trigger...");
}, true);
$document.bind('keydown', function (e) {
if(e.keyCode >= 48 && e.keyCode <= 90) {
scope.modal.isOpen = true;
elem.find('input')[0].focus();
}
..........
});

You should keep watch on property which shouldn't have scope in the string given to $watch function.
scope.$watch('modal.isOpen', function(newValue, oldValue) {
And the while modifying scope from custom event, wouldn't update binding. You need to kick digest cycle using $timeout/$apply() to update binding.(If any code ran ouside of angular context, angular doesn't run digest cycle to update bindings).
$document.bind('keydown', function(e) {
if (e.keyCode >= 48 && e.keyCode <= 90) {
$timeout(function() {
scope.modal.isOpen = true;
elem.find('input')[0].focus();
});
}
..........
});

Related

Call scope function inside onkeydown event

I have the following html:
<input type="checkbox" ng-model="user.show_value" ng-blur="update_show_value()">
A value (true / false) is fetched from the database and passed to the ng-model. Depending on it, the checkbox is checked / uncheked. The function inside ng-blur triggers the update in the database and works:
$scope.update_show_value() = function() {
if ($scope.user.show_value != undefined) {
$scope.loading = true;
//IF VALUE IS VALID, CALL THE UPDATEPIN FUNCTIONn
User.updatevalue($scope.user)
//IF SUCCESSFUL, GET VALUE
.success(function(data) {
$scope.loading = false;
$scope.formData = {}; //CLEAR FORM SO THAT USER CAN ENTER NEW DATA
$scope.user.show_value = {type : $scope.user[0].show_value}; //PASS VALUE IN OUR SCOPE
});
}
};
The issue is that I would have to use the checkbox from other devices that don't support the click event. From these devices I should use the equivalent of enter (keycode 13). So I added the onkeydown event to detect when the enter key is being pressed on the checkbox. Using an example from w3schools, I see it works (here is the example http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_event_key_keycode3)
<input type="checkbox" ng-model="user.show_value" onkeydown="keyCode(event)" ng-blur="update_show_value()">
Now I want to call the update function when the onkeydown event detects that the code 13 was pressed. Something like this:
<script>
function keyCode(event) {
var x = event.keyCode;
if (x == 13) {
alert ("You pressed the Escape key!");
update_show_value();
}
}
</script>
However, calling update_show_value inside the keycode function does not work. Actually, adding update_show_value inside the keycode function causes everything else not to work (ex. the alert)
So for some reason I think that scope functions cannot be called inside javascript functions. If that is true, is there a workaround?
You can get the scope object outside of Angular by using:
angular.element(event.target).scope(); // and then call whatever functions you want to on that scope object
You can define your own directive to handle keydown
angular.directive('myKeydown', [ function () {
return {
link: function(scope, elem, attrs) {
element.bind('keydown', function() {
scope.update_show_value();
});
}
};
}]);
Or just use ng-keydown instead: https://docs.angularjs.org/api/ng/directive/ngKeydown :
$scope.keyCode = function($event) {
. . .
$scope.update_show_value();
};
Remove () from $scope.update_show_value
Try Below Code:
<script>
var app=angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.update_show_value = function() {
alert(1);
};
});
</script>

Getting event.key as undefined intermittently on "keydown" event, with Chrome browser

I am using the code below in an angular custom directive code to know the keys pressed. It works fine however event.key starts giving undefined intermittently. If i am clearing the cache and trying it again, it starts working again. What could be the possible issue ?
<input type="text" input-styler="" class="form-control" id="input-phrase" ng-model="home.inputPhrase" autocomplete="off">
angular
.module('myApp')
.directive('inputStyler', inputStyler);
function inputStyler() {
var directive = {
restrict: 'A',
link: link
};
function link(scope, element, attrs){
element.bind("keydown", function (event) {
console.log(event.key);
if((!event.ctrlKey) && (event.key !== " ") && (event.key.length == 1)){
scope.home.inputPhrase += event.key;
}
});
element.on("cut copy paste", function(event){
event.preventDefault();
});
};
return directive;
}

Directive error $rootScope:infdig Infinite $digest Loop

I downloaded a directive that receives only numbers and has some additional options; but, after running it I get a rootScope error in one of the options that is:
<input type="text" ng-model="mynumber" nks-only-number allow-decimal="false" />
I believe the false conditional is making this error appear, but I don't know why.
Here is the demo:
http://jsfiddle.net/RmDuw/896/
Code:
(function(){
angular.module('myApp', [])
.directive('nksOnlyNumber', function () {
return {
restrict: 'EA',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngModel, function(newValue, oldValue) {
var spiltArray = String(newValue).split("");
if(attrs.allowNegative == "false") {
if(spiltArray[0] == '-') {
newValue = newValue.replace("-", "");
ngModel.$setViewValue(newValue);
ngModel.$render();
}
}
if(attrs.allowDecimal == "false") {
newValue = parseInt(newValue);
ngModel.$setViewValue(newValue);
ngModel.$render();
}
if(attrs.allowDecimal != "false") {
if(attrs.decimalUpto) {
var n = String(newValue).split(".");
if(n[1]) {
var n2 = n[1].slice(0, attrs.decimalUpto);
newValue = [n[0], n2].join(".");
ngModel.$setViewValue(newValue);
ngModel.$render();
}
}
}
if (spiltArray.length === 0) return;
if (spiltArray.length === 1 && (spiltArray[0] == '-' || spiltArray[0] === '.' )) return;
if (spiltArray.length === 2 && newValue === '-.') return;
/*Check it is number or not.*/
if (isNaN(newValue)) {
ngModel.$setViewValue(oldValue || '');
ngModel.$render();
}
});
}
};
});
}());
I believe the problem, looking at your pasted code (not the different JSFiddle), is that ngModel.$render() gets called twice. If I delete it from either the attrs.allowDecimal == false conditional or the end isNaN(newValue) conditional, the code runs fine.
Since I'm not sure what your end goal is, I've neglected to actually rewrite your code. But, that solved the infinite $digest loop error.

AngularJS directive not executing everytime

I have written an AngularJS directive to validate percent value,
AngularJS Directive
app.directive('validatePercent', function () {
return {
restrict: 'A',
link: function ($scope, elem, attr) {
$scope.$watch(function () { return elem.val(); },
function (newVal, oldVal) {
console.log("old : ", oldVal);
console.log("new : ", newVal);
if (newVal < 0 || newVal > 100)
{
elem.val(oldVal);
}
}
);
}
};
});
Here's my HTML
<input validate-percent ng-model="obj.progress" type="number" class="form-control" />
Note : obj.progress is of type int, also input type is number
The issue is when I try to change value of this input field multiple times quickly one after the another value goes to -1 or even 101 sometimes. Although condition in my directive is newVal < 0 || newVal > 100
Need help.
UPDATE 1:
This happens only when user changes values using mouse wheel. It doesn't happens while increment or decrements by arrow keys on keyboard.
Instead of using $watch, you can handle it using focus/blur events.
app.directive('validatePercent', function () {
return {
restrict: 'A',
link: function ($scope, elem, attr) {
var oldVal = elem.val();
elem.bind('focus', function(e) {
oldVal = elem.val();
});
elem.bind('blur', function(e) {
if ( elem.val()< 0 || elem.val() > 100)
{
elem.val(oldVal);
}
});
}
};
});
Hope it helps.

IE input clear icon sometimes not trigger the change event

I'm using AngularJS in our project and I find IE provides a clear icon on every input box by default. But when I click the 'X' icon the change event won't be fired.
Can someone kindly help me find a simple way to solve this issue?
It worked in plnkr, it's very weird...
$scope.$watch('model.search', function(search){
console.log(search);
}, true);
http://plnkr.co/edit/U8BMJtBnyK1oxviMV9aL?p=preview
I remove all the class and analytics in the input element, it still can not trigger the change...
Thanks in advance!
I would stop worrying about it by hiding this feature-
input::-ms-clear {
display: none;
}
That is just one more of countless non-standard browser features that Microsoft introduce that contain missing functionality.
Our time is too precious. Coding specifically for IE has been a pain for a decade...
I was able to solve this using the following directive, for those looking for an alternative to hiding the clear button. It may not be perfect yet, so I welcome any feedback :)
angular
.module('yourModuleName')
.directive('input', FixIEClearButton);
FixIEClearButton.$inject = ['$timeout', '$sniffer'];
function FixIEClearButton($timeout, $sniffer) {
var directive = {
restrict: 'E',
require: '?ngModel',
link: Link,
controller: function () { }
};
return directive;
function Link(scope, elem, attr, controller) {
var type = elem[0].type;
//ie11 doesn't seem to support the input event, at least according to angular
if (type !== 'text' || !controller || $sniffer.hasEvent('input')) {
return;
}
elem.on("mouseup", function (event) {
var oldValue = elem.val();
if (oldValue == "") {
return;
}
$timeout(function () {
var newValue = elem.val();
if (newValue !== oldValue) {
elem.val(oldValue);
elem.triggerHandler('keydown');
elem.val(newValue);
elem.triggerHandler('focus');
}
}, 0, false);
});
scope.$on('$destroy', destroy);
elem.on('$destroy', destroy);
function destroy() {
elem.off('mouseup');
}
}
}

Categories