angular js event enter to call a function on the element tr - angularjs

I can move up and down with the keyboard keys but i cannot get the enter event correct
**Controller**
$scope.myFunction = function()
{
alert('sadsad');
alert('hi');
}
**Also i added directive like this**
.directive('ngEnter', function ()
{
restrict:'use strict';
return {
link: function (scope, elements, attrs) {
elements.bind('keydown keypress', function (event) {
if (event.which === 13) {
scope.$apply(function () {
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
}
};
});
**Below is the view code on which i m calling directive and function**
<tr class="find"ng-repeat="busServices in " ng-click="setSelected(busServices.bus_travel_id,this.busServices,$event)" ng-class="{selectedsd:busServices.bus_travel_id === idSelected}" ng-mouseover="ShowHideBoarding($event,this.busServices,true)" ng-mouseleave="ShowHideBoarding($event,false)" ng-init="($first) ? setSelected(busServices.bus_travel_id,this.busServices) : ''" ng-enter="myFunction()"></tr>
ng-enter doesnt get called at all.
what can i do so that ng enter can work.

Try something like this
.directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keypress", function (event) {
if(event.keyCode === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
The restrict option can be omitted.
EDIT: You will have to add an attribute to your <tr> so that they can be focussed and receive key* events:
<tr tabindex="0" ....>
Replace 0 with other numbers for more of your focussable <tr>

Related

orderBy doesn't seem to work after editing result values in angular

I wrote this directive editable-field to be able to edit values after the form search results.
<table>..
<tr ng-repeat="emp in srchCtrl.emps | orderBy : 'salary'">
<td>{{emp.id}}</td>
<td editable-field="emp.name"></td>
<td editable-field="emp.salary"></td>
<td editable-field="emp.department.name"></td>
</tr>
</table>
After I change the value, the values change, but, how can I ask angular to refresh results with orderBy filter using new values?
.controller('MainController')..
var self = this;
self.emps = [ ]; // this will be populated after the promise resolves.
}
I see the emps getting updated by printing them.
.directive('editableField', function () {
var self = this || {};
self.link = function (scope, elm, attr, editCtrl) {
var previousValue;
editCtrl.edit = function () {
editCtrl.editMode = true;
previousValue = editCtrl.model;
elm.find('input')[0].focus();
};
editCtrl.save = function () {
editCtrl.editMode = false;
};
editCtrl.cancel = function () {
editCtrl.editMode = false;
editCtrl.model = previousValue;
};
}
return {
scope: {},
controllerAs: 'editCtrl',
controller: function () {
},
bindToController: {
model: '=editableField'
},
link: self.link,
templateUrl: '../../../templates/row-edit.html'
};
})
This is my editableField directive which binds editableField field on the row to the model in the controller which is editCtrl.
On save I am calling the callback function on the main controller which has reference to the emps
If I call scope.$apply() in any of the editCtrl's save, it says "$apply already in progress"
$scope.$watch(angular.bind(self, function () {
return self.emps; // `this` IS the `this` above!!
}), function (newVal, oldVal) {
// now we will pickup changes to newVal and oldVal
if (newVal === oldVal) { console.log('first time'); return; } // AKA first run
console.log('self.emps updated');
});
I see the value getting updated on changing values in the UI.
scope.$watch(angular.bind(editCtrl, function () {
return editCtrl.model;
}), function (newVal, oldVal) {
if (newVal === oldVal) { console.log('model first time'+newVal); return; }
console.log('model updated');
});
Your editable-field directive should have something like the following:
scope: {
"emp": "="
}
So that a change in the passed value to editable-field is reflected back to the parent Controller / Directive.

Angularjs : directive not called

I have an input :
<table>
...
<td style="width:59px"><input ng-model="myModel.propertyOne" ng-blur="persistValue(myModel)" enter-as-tab></td>
<td style="width:59px"><input ng-model="myModel.propertyTwo" ng-blur="persistValue(myModel)" enter-as-tab></td>
with its directive
angular.module('bioandbioApp').directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
event.preventDefault();
var elementToFocus = element.next('td').find('input')[1];
if(angular.isDefined(elementToFocus))
elementToFocus.focus();
}
});
};
});
This directive is called when user press Enter, and set the focus to the input of the next tag.
My problem is that the directive is called but elementToFocus.focus() is not called so the focus is not set.
I don't understand why. Does anyone know?
http://jsfiddle.net/tomy29/vpaqt29d/105/
Thanks
You need to find the parent first and then go the next element.
Try the below code:
var app = angular.module("ap", []);
app.controller("con", function ($scope) {
$scope.persons = [{
name: 'Susan',
age: 1
}, {
name: 'Peter',
age: 1
}, {
name: 'Jack',
age: 2
}];
});
app.directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if (event.which === 13) {
event.preventDefault();
console.log("parent");
console.log(element.parent())
var elementToFocus = element.parent().next('td').find('input')[0];
console.log("next element");
console.log(elementToFocus);
if (angular.isDefined(elementToFocus)) elementToFocus.focus();
}
});
};
});
JSFiddle
--EDIT--
This definitely can be optimized but a crud way of doing is as below:
<body ng-app="ap" ng-controller="con">
<h4>Pressing <i>Enter/Return</i> in the <i>Age</i> field will iterate through the ages</h4>
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr ng-repeat='person in persons'>
<td>
<input type='text' name="personName" ng-model="person.name" enter-as-tab />
</td>
<td>
<input type='number' name="personAge" ng-model="person.age" enter-as-tab/>
</td>
</tr>
</table>
</body>
var app = angular.module("ap", []);
app.controller("con", function ($scope) {
$scope.persons = [{
name: 'Susan',
age: 1
}, {
name: 'Peter',
age: 1
}, {
name: 'Jack',
age: 2
}];
});
app.directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if (event.which === 13) {
event.preventDefault();
console.log("parent");
console.log(element.parent())
var elementToFocus = element.parent().next('td').find('input')[0];
console.log('next element');
console.log(elementToFocus);
if (angular.isDefined(elementToFocus)) {
elementToFocus.focus();
} else {
element.parent().parent().next('tr').find('input')[0].focus();
}
}
});
};
});
JSFiddle
you can use this code
$(this).closest('td').next('td').find('input')[0];
Currently, this is the input field of the current td. So, by that, you can find the input to the next of the current td.
Here is the working JSFIDDLE
Although your fiddle is using static contents and a fixed set of fields, below is how I achieved the solution, however, depending on the dynamic content and your requirements, the solution may vary:
app.directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
event.preventDefault();
var elementToFocus;
if(attrs["name"] == "personAge"){
elementToFocus = element.parent().parent().next().find('input')[0];
}else{
elementToFocus = element.parent().next().find('input')[0];
}
if(angular.isDefined(elementToFocus))
elementToFocus.focus();
}
});
};
});

Can I simplify clicking the enter key with AngularJS?

I already have this code that I came up with:
In my outer controller:
$scope.key = function ($event) {
$scope.$broadcast('key', $event.keyCode)
}
In my inner controller (I have more than one like this)
$scope.$on('key', function (e, key) {
if (key == 13) {
if (ts.test.current) {
var btn = null;
if (ts.test.userTestId) {
btn = document.getElementById('viewQuestions');
} else {
btn = document.getElementById('acquireTest');
}
$timeout(function () {
btn.focus();
btn.click();
window.setTimeout(function () {
btn.blur();
}, 500);
})
}
}
});
Is there another way that I could simplify this using some features of AngularJS that I have not included here?
Please check this gist, https://gist.github.com/EpokK/5884263
You can simply create a directive ng-enter and pass your action as paramater
app.directive('ngEnter', function() {
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
if(event.which === 13) {
scope.$apply(function(){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
HTML
<input ng-enter="myControllerFunction()" />
You may change the name ng-enter to something different, because ng-** is a reserved by Angular core team.
Also I see that your controller is dealing with DOM, and you should not. Move those logic to other directive or to HTML, and keep your controller lean.
if (ts.test.userTestId) {
btn = document.getElementById('viewQuestions'); //NOT in controller
} else {
btn = document.getElementById('acquireTest'); //NOT in controller
}
$timeout(function () {
btn.focus(); //NOT in controller
btn.click(); //NOT in controller
window.setTimeout(function () { // $timeout in $timeout, questionable
btn.blur(); //NOT in controller
}, 500);
})
What i've done in the past is a directive which just listens for enter key inputs and then executes a function that is provided to it similar to an ng-click. This makes the logic stay in the controller, and will allow for reuse across multiple elements.
//directive
angular.module('yourModule').directive('enterHandler', [function () {
return{
restrict:'A',
link: function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
var key = event.which ? event.which : event.keyCode;
if (key === 13) {
scope.$apply(function () {
scope.$eval(attrs.enterHandler);
});
event.preventDefault();
}
});
}
}
}]);
then your controller becomes
$scope.eventHandler = function(){
if (ts.test.current) {
var btn = ts.test.userTestId
? document.getElementById('viewQuestions')
: document.getElementById('acquireTest');
$timeout(function () {
btn.focus();
btn.click();
window.setTimeout(function () {
btn.blur();
}, 500);
})
}
}
and your markup can then be
<div enter-handler="eventHandler()" ></div>

AngularJS one click on element and click+hold more 5 seconds

I have the div element and I need catch event of one click and click and hold.
If happened one click of this div, i should call function 1 in scope, if click and hold (more of 5 seconds) i should call function 2 in scope.
Create a directive on-click-and-hold and use it.
Directive
directive('onClickAndHold', function ($parse, $timeout) {
return {
link: function (scope, element, attrs) {
var clickAndHoldFn = $parse(attrs.onClickAndHold);
var doNotTriggerClick;
var timeoutHandler;
element.on('mousedown', function () {
$timeout.cancel(timeoutHandler);
timeoutHandler = $timeout(function () {
clickAndHoldFn(scope, {$event: event})
}, 5000)
});
element.on('mouseup', function (event) {
$timeout.cancel(timeoutHandler);
});
if (attrs.onClick) {
var clickFn = $parse(attrs.onClick);
element.on('click', function (event) {
if (doNotTriggerClick) {
doNotTriggerClick = false;
return;
}
clickFn(scope, {$event: event});
scope.$apply();
});
}
}
}
})
Markup
<div on-click-and-hold="f2()" on-click="f1()"></div>
Controller
controller('AppCtrl', function ($scope) {
$scope.f1 = function () {
console.warn('inside f1');
}
$scope.f2 = function () {
console.warn('inside f2');
}
})
If you want to handle only the click event use ng-click instead of on-click-and-hold.
Working Plnkr

Using the enter key as tab using only angularjs and jqlite

I have looked at multiple threads and tried a vast variety of solutions.
Quite frankly I think I am losing my mind.
I have an ng-repeat with inputs. All that needs to happen is that when the user presses enter, it should shift focus to the next input, basically simulating the tab key functionality.
The code (incomplete):
HTML:
<body ng-app="ap" ng-controller="con">
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr ng-repeat='person in persons'>
<td>
<input type='text'
name="personName"
ng-model="person.name"
/>
</td>
<td>
<input type='number'
name="personName"
ng-model="person.age"
enter-as-tab
/>
</td>
</tr>
</table>
JS:
var app = angular.module("ap", []);
app.controller("con", function ($scope) {
$scope.persons = [
{ name: 'Susan', age: 1 },
{ name: 'Peter', age: 1 },
{ name: 'Jack', age: 2 }
];
});
app.directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
event.preventDefault();
// Go to next age input
}
});
};
});
Here is a link to the fiddle: fiddle
Ok, so I figured it out. Wasn't that difficult after all. Just got caught up in the whole "don't think jQuery while using Angular" mindset.
Here is the directive that I implemented:
app.directive('enterAsTab', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
event.preventDefault();
var elementToFocus = element.next('tr').find('input')[1];
if(angular.isDefined(elementToFocus))
elementToFocus.focus();
}
});
};
});
Here is the link to the working fiddle: enter-as-tab
Starting from #avn's solution I made some changes to find recursively and focus to the next input text or input number, but only if the value is valid, or send the form. Was designed for ionic forms but could be adapted for any angular forms:
app.directive('enterAsTab', function () {
return {
restrict: 'A',
require: '^ngModel',
link: function (scope, element, attrs, ctrl) {
element.bind("keydown keypress", function (event) {
function isKeyEnterAndValid(){
return event.which === 13 && ctrl.$valid;
}
function nextItem(div, tag){
var next = div.next(tag);
if (!next) return nextItem(div, 'label');
return next;
}
function isTypeTextOrNumber(input){
return ['text', 'number'].indexOf(input.attr('type')) === -1;
}
function findInput(div){
var next = nextItem(div, 'div');
if (!next) return;
var input = next.find('input');
if (!input || isTypeTextOrNumber(input)){
return findInput(next);
}
return input[0];
}
if(isKeyEnterAndValid()) {
var nextInput = findInput(element.parent());
if(angular.isDefined(nextInput)){
event.preventDefault();
nextInput.focus();
}
}
});
}
};
});

Resources