call a controller scope function on keyPress from directive in AngularJS - angularjs

Below is my controller scope function :
MyApp.controller("MyController", function ($scope, MyService) {
$scope.hposition = "";
$scope.selectedRow = 0;
$scope.pSearch = {};
$scope.selectH = function (index, hId, myModel) {
$scope.selectedRow = index;
var resultList = MyService.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close');
})
} });
And I have a directive for keyboard events - keydown, keyup and keypress.
MyApp.directive('arrowSelector', ['$document', function ($document) {
return {
restrict: 'A',
link: function (scope, elem, attrs, ctrl) {
$document.bind('keydown', function (e) {
//if (elemFocus) {
if (e.keyCode == 38 || e.keyCode == 37) {
console.log(scope.selectedRow);
if (scope.selectedRow == 0) {
return;
}
scope.selectedRow--;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 40 || e.keyCode == 39) {
if (scope.selectedRow == scope.hlist.length - 1) {
return;
}
scope.selectedRow++;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 13) {
var resultList = scope.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close');
});
scope.$apply();
e.preventDefault();
}
});
}
};}]);
I tried calling the function scope.selectH(), but it is not working.
How can I call my selectH function when e.keyCode==13? Is there any other better way to do keyboard up and down arrow events ?

You just need to add scope in your directive like scope: { someCtrlFn: '&callbackFn' },
and add it to your html where you have used this directive like
<div ng-controller="MyCtrl">
<div my-directive callback-fn="ctrlFn(arg1)"></div>
Whole example as here
One more thing is that you can directly call your service from your directive and get response there by injecting service provider.
MyApp.directive('arrowSelector', ['$document','MyService', function ($document) { return {
restrict: 'A',
link: function (scope, elem, attrs, ctrl) { $document.bind('keydown', function (e) {
//if (elemFocus) {
if (e.keyCode == 38 || e.keyCode == 37) {
console.log(scope.selectedRow); if (scope.selectedRow == 0) {
return;
}
scope.selectedRow--;
scope.$apply();
e.preventDefault();
} if (e.keyCode == 40 || e.keyCode == 39) {
if (scope.selectedRow == scope.hlist.length - 1) {
return;
}
scope.selectedRow++;
scope.$apply();
e.preventDefault();
}
if (e.keyCode == 13) { var resultList = MyService.selectH(hId, $scope.hposition, myModel);
resultList.then(function (response) {
$scope.myModel= response.data;
$("#divlookup").dialog('close'); });
scope.$apply();
e.preventDefault();
}
});} };}]);

Related

Angular Directive working in all controllers

I have following directive:
app.directive('remoteDirective', ['$location', 'playlistService', 'videoService', function ($location, playlistService, videoService) {
return {
restrict: 'A',
link: function (scope, el, attrs) {
$('body').on('keydown', function (evt)
{
if (evt.keyCode === 38) //Up Arrow
{
scope.currentChannel.number++;
$('#modal1').openModal();
videoService.playVideo(playlistService.getChannel(scope.currentChannel.number).file);
scope.currentChannel.name = scope.playlist[scope.currentChannel.number].title;
scope.$apply();
}
else if (evt.keyCode === 40) //Down Arrow
{
scope.currentChannel.number--;
$('#modal1').openModal();
videoService.playVideo(playlistService.getChannel(scope.currentChannel.number).file);
scope.currentChannel.name = scope.playlist[scope.currentChannel.number].title;
scope.$apply();
}
else if (evt.keyCode === 13) //Enter
{
$('.button-collapse').sideNav('show');
}
else if (evt.keyCode === 27) //Esc
{
$location.path('settings');
scope.$apply();
}
});
}
};
}]);
And i Use it in my main controller like this
<div class="valign-wrapper" style="width: 100%; height: 100%" remote-directive >...</div>
Problem is, that this directive fires in all controller, not only in my main... How to solve? I want to have another actions for theese keys in other controllers...

Uneditable trailing text in textarea

I have been fighting with this for a couple of days to no avail.
I need to have a textarea with uneditable text trailing on the end.
Here is a fiddle with the text in the beginning of the text area, the requirement is to have it on the end. Anyone have any insight how to achieve this?
http://jsfiddle.net/codemonkeytony/3ew5h6bf/7/
var partialApp = angular.module("partialApp", []);
partialApp.directive('partialReadonly', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.on('keypress, keydown', function (event) {
console.log(scope.bbb);
console.log(event);
var readOnlyLength = attrs["partialReadonly"].length;
if ((event.which != 37 && (event.which != 39)) && ((elem[0].selectionStart < (scope.bbb - readOnlyLength )) || ((elem[0].selectionStart != (scope.bbb - readOnlyLength )) && (event.which == 8)))) {
event.preventDefault();
}
});
$(window).load(function () {
elem[0].value = attrs["partialReadonly"];
});
}
};
});
I have updated the logic on keypress event handler. Check this updated fiddle, if you want this behaviour.
partialApp.directive('partialReadonly', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var readOnlyText = attrs["partialReadonly"];
var readOnlyLength = readOnlyText.length;
var ele = elem[0];
elem.on('keypress, keydown', function (event) {
var actualTextLength = ele.value.length - readOnlyLength;
var readOnlyTextStartIndex = actualTextLength;
if (elem[0].selectionStart > readOnlyTextStartIndex) {
event.preventDefault();
}
});
$(window).load(function () {
elem[0].value = attrs["partialReadonly"];
});
}
};
});

How to allow a number with digit limit and without decimal,and negative ina textfield using AngularJS directive

Here is my code.But its not working in my directive .Please help me to show errors
When initially run I enter characters(other than number) in two times it will allowed. For Eg press 'W' in two times it will allwed in that textfield.
What is the error in this code?
Here is my script
var myApp = angular.module('myApp', []);
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(attrs.limitDigit=="true"){
// attr.$set("ngTrim", "false");
var limitLength = parseInt(attrs.awLimitLength, 10);// console.log(attrs);
if(ngModel.$viewValue.length>limitLength){
newValue = ngModel.$viewValue.substring(0, limitLength);
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();
}
});
}
};
});
Here is my textfield in html file
<b>NumberLimited Only 4 Digits</b><br>
<input type="text" nks-only-number ng-model="mynumber6" aw-limit-length="4" allow-decimal="false" allow-negative="false" limit-digit="true" /><br>
Please use the following directives
/*
*Directive to Numbers only
*use - numbers-only
*/
myApp.directive('numbersOnly', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function fromUser(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/g, '');
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
}
return transformedInput;
}
return false;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});
/*
*Directive to Max legth to prevent type
*use - my-maxlength
*/
myApp.directive('myMaxlength', function() {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
var maxlength = Number(attrs.myMaxlength);
function fromUser(text) {
if (text.length > maxlength) {
var transformedInput = text.substring(0, maxlength);
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
return transformedInput;
}
return text;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
})
And use like
<input name="field1"
type="text"
ng-model="model1"
numbers-only
my-maxlength="4">
Hopes this will help you !
Had something similar recently. Altered the input box:
<input {normal attributes here} data-ng-keydown="vm.checkNumber($event)" max="9999" />
Then in my controller:
vm.checkNumber = checkNumber;
function checkNumber(e) {
var keyCode = e.which || e.keyCode;
if (([9, 8, 13, 27, 37, 38, 39, 40].indexOf(keyCode) > -1) ||
(keyCode >= 49 && keyCode <= 57) ||
(keyCode >= 96 && keyCode <= 105)) {
return;
} else {
event.preventDefault();
}
}

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>

Limited to write only a-z in angular

I want to let user to write just english character not number or any languages .
here is my fiddle : Demo but it's not working .
app.directive('validcharEn', function () {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function (val) {
if (angular.isUndefined(val)) {
var val = '';
}
var clean = val.replace(/[^a-z]/g, '');
var decimalCheck = clean.split('.');
if (!angular.isUndefined(decimalCheck[1])) {
decimalCheck[1] = decimalCheck[1].slice(0, 2);
clean = decimalCheck[0] + '.' + decimalCheck[1];
}
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function (event) {
if (event.keyCode === 10) {
event.preventDefault();
}
});
}
};
});
Am i missing something ?
You can use the ng-pattern-restrict directive:
<input type="text" ng-pattern-restrict="^[a-z]*$" />
Here'a an example: http://jsfiddle.net/upcvoa4L/
How about this : Fiddle , clean and simplest way to do it .
app.directive('validEn', function() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if(!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function(val) {
var clean = val.replace( /[^a-z]+/g, '');
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function(event) {
if(event.keyCode === 32) {
event.preventDefault();
}
});
}
};
});
HTML
<input type="text" ng-model="employee.age" valid-en />
Update
or maybe for email input :
Fiddle
var clean = val.replace( /[^0-9+.+a-z+#]+/g, '');
Hope this help

Resources