ng-blur is not called from a function triggered by ng-keyup - angularjs

so I have a ng-blur function that correctly fires if I do this
$scope.disableReturnButton = function($event){
document.onkeyup=function(e) {
if(e.which == 13){
$event.target.blur();
return false;
}
}
}
however if I try to set the keyup event on the element only, it doesn't seem to trigger ng-blur when the blur event happens
$scope.disableReturnButton = function($event){
if($event.which == 13){
$event.target.blur();// this blurs the element but doesn't trigger the ng-blur
return false;
}
}
here's the markup
<span contenteditable="true" class="blanks"
ng-blur="blurredWhy($event)"
ng-focus="focusedWhy($event)"
ng-bind="data.why"
ng-keyup="disableReturnButton($event)"></span>

If you use return false; in the event handler, with jQuery it will stop propagation and stop other events from firing in the chain. Since Angular uses jQuery lite (or you have jQuery full as well on the page) returning false will kill upstream events.
The first example would work because it uses the document.onkeyup which registers the event listener outside of jQuery.
See event.preventDefault() vs. return false

Related

Ng Touch MouseUp Doesn't Apply

I have a plunk here:
https://plnkr.co/edit/EKpqNwQEHHHiFoiv43s3
I am having an issue where my ng-touch on a phone or tablet is firing on the mousedown but not on the mouseup, resulting in the incrementation going on ad infinitum which is not desired.
Code here:
$scope.mouseDown = function(dir) { //this function fires when I press down on a phone
promise = $interval(function() {
if (dir === "up")
$scope.quantity++;
else
$scope.quantity--;
}, 100);
};
$scope.mouseUp = function() { //this function doesn't seem to fire when I stop the press on a phone
$interval.cancel(promise);
};
mouseup does not fire on touch devices. ngTouch does not give you directives to bind touch events unfortunately. You'll need to grab a custom directive that will allow you to bind touchstart and touchend events. There are a few out there. I've created a gist with one I've written that has worked well for me on several projects:
https://gist.github.com/Toddses/fdd862648e10530038550e253212d9c1
With this, as is, you can bind flux-touchstart and flux-touchend in the markup the same way you bind ng-mousedown and ng-mouseup.

How to let angular $asyncValidator fire on blur but normal validators on input

Is it possible to let angular 1.3 $asyncValidators only fire on blur and not as the user inputs? I want the $validators to behave as per default.
I know I can use ng-model-options to update the model onBlur but then all validations are fired on blur.
Currently (angularjs version 1.3) there is no mechanism to do this.
In the end I added a blur event to fire the validators and then set the validity
element.on('blur', function () {
if (ngModel.$dirty) {
doServerSideValidation();
} else {
ngModel.$setValidity(key, true);
}
});
The doServerSideValidation() function will set the validity of the ngModel after doing the request.

$watch on clientWidth isn't working

Inside of my directive I have this and it works only in the beginning, and whenever I resize later it never fires.
scope.$watch ->
cw: element[0].clientWidth
,(newValue, oldValue)->
if newValue.cw isnt oldValue.cw
console.log "changed"
,true
Your function looks right to me, but it's important to note that it won't fire on resize unless you manually trigger a digest on the resize event.
Without this, angular doesn't realise there's been an event that should trigger a digest, and so none happen.
Try adding this (remember to inject $window):
angular.element($window).bind('resize', ()->
scope.$apply();
)
Just like Jason Goemaat said, its because Watches are only checked on a $digest cycle
Depending on how the way your element is resized maybe this example may help you.
Here is a menu that expands it self when pressed on the arrow.
<div class="menu" ng-class="{'expanded' : main.expanded}">
<div class="menu-handler" ng-click="main.expanded = !main.expanded">
</div>
</div>
The menu is expanded by a ng-click that makes a change on the scope, in this case its a boolean var that acts as a flag. As the opening of the menu is made throught the change in the scope it calls the $digest cycle iterating through all $watch.
scope.$watch(function() {
return element[0].clientWidth;
}, function(oldValue, newValue) {
console.log(oldValue, newValue);
});
You can view the full example in this JSfiddle
https://jsfiddle.net/owenbcal/zf17s0mL/
Hope i was helpfull.
the way I know about watching this kind of values is making a function that is fired once the value changes so then I watch that function :
in the service:
this.getDataOut = function () {
return self.dataOut;
};
in the controller:
$scope.$watch(dataService.getDataOut, function() {
$scope.dataOut = dataService.dataOut;
});

Angular: manipulating event firing order - namely ng-blur & ng-click?

I have two html elements: <aleph> and <beth>. The element <aleph> has a ng-blur attribute and the element <beth> has the ng-click attribute.
If I am in focus on elment <aleph> and click on <beth> it appears (according to experimentation) that the ng-blur will fire first and ng-click will fire next.
http://jsfiddle.net/UTn5y/70/
Will that always be the behavior?
Could I change that behavior without any effort?
Will that always be the behavior?
Yes, the blur event will always be fired first
Could I change that behavior without any effort?
No you can not change the behavior. However, you can manage it by hand. You can use $timeout in your ng-blur callback, and check for a variable which can be manipulated by ng-click.
function ngClick () {
$scope.clicked = true;
// rest of your code
}
function ngBlur () {
$scope.clicked = false;
$timeout(function () { // will be executed after ngClick function in case of click
if ($scope.clicked) {
return;
}
// rest of your code
})
}
Here is a working version:
http://jsfiddle.net/zhfew91j/2/

applying ng-blur and keydown (to capture enter key) on the same input element shows $apply already in progress error

I am developing an application in which there are rows one after other which contain input boxes.I have attached ng-blur and ng-keydown events to the input boxes.
On ng-keydown, i check if an enter was pressed then set focus to the next input box but as ng-blur is also attached to the input, it also fires when i try to set focus to the next input which throws $apply already in progress error on the console and hence the code on ng-blur fails to run.
Html:
<div class="main" ng-app ng-controller="appCtrl">
<input type="text" ng-repeat="name in names" ng-model="name" ng-blur="checkUpdate(name)" ng-keydown="keydownoperations(names,$event)"/>
</div>
<script src="http://code.jquery.com/jquery-2.1.1.js"></script>
JS:
function appCtrl($scope){
$scope.names = ['John','Smith','Ravi'];
$scope.checkUpdate = function(name){
console.log(name);
}
$scope.keydownoperations = function(names,event){
var $this = $(event.target);
if(event.which === 13) // Enter key
{
if($this.next().length) // if the adjacent sibling exists set focus
{
$this.next().focus();
}
}
}
}
Please see this fiddle http://jsfiddle.net/jitender60/qDZa9/4/ to get a clear view of my problem
The $scope.$apply() is called automatically by both ng-blur and ng-keydown.
The problem occurred because you trigger the focus event programmatically inside the keydown event handler. That will eventually trigger a blur event on a previously active element which in this case also has ng-blur on it.
Angular doesn't know if the blur event come from a user interaction or is triggered programmatically.
You could avoid the problem by defer the .focus() execution, may be inject a $timeout service and use it like this:
$timeout(function () {
$this.next().focus();
}, 0);
Hope this helps.

Resources