I'm using Angular JS and I need to write a directive that will initiate a function ONLY when the spacebar (32) gets pressed twice in a row. The app has forms also and users might need to actually hit space twice in a textarea or input field, so we need to account for that as well. We also need to make sure the page doesn't scroll when pressing the spacebar, but doing event.preventDefault(); actually prevents the spacebar from being used to type a space in a form element. Any ideas as to how to accomplish this? Is it even possible? I might consider binding to a key combination instead if this is too difficult. Here is a sample of what I have so far:
(function() {
"use strict";
angular
.module("app.spaceFunc")
.directive("triggerFunc", triggerFunc);
triggerFunc.$inject = ["$window"];
/* #ngInject */
function triggerFunc($window) {
var directive = {
link: link,
restrict: "A"
};
return directive;
function link(scope, element, attrs) {
var upHitOnce = false;
angular.element($window).bind("keydown", function(event) {
if ((event.keycode || event.which) === 32) {
//Prevents page scrolling (spacebar default's behaviour)
event.preventDefault();
if (upHitOnce) {
//some function gets executed here
console.log("Spacebar pressed twice");
upHitOnce = false;
} else {
upHitOnce = true;
}
} else {
upHitOnce = false;
}
});
}
}
})();
The directive is attached to the body element
<body trigger-func>
Related
I have a custom icon component using isolate scope where a user can define what he or she wants to happen on ng-click:
<ers-icon name="history" ng-click="ctrl.clickAlert('history')"></ers-icon>
This calls a method from within the user's controller as follows:
this.clickAlert = function (icon) {
alert("You selected the " + icon + " icon.");
}
I need to add enter key functionality to the icon component without adding any other code, from I have above, to my html element. So essentially listen for the enter key press from within the directive and evaluate the ng-click directive on ers-icon. Here is what I have as the icon directive:
// on click works fine
.on("click", (event:JQueryEventObject):void => {
if (this.ngDisabled) {
event.preventDefault();
event.stopPropagation();
}
});
}
//execute whatever function is specified inside ng-click on enter key press
.on("keydown", (event:JQueryEventObject):void => {
if (event.keyCode === 13) {
if (this.ngDisabled) {
event.preventDefault();
event.stopPropagation();
} else {
// need to execute ng-click here
// this try doesn't work, gives me undefined
$scope.$apply(() => {
$scope.$eval($attr.ngClick);
}
}
}
});
This runs fine on enter key press but I can't get the controller function defined on ng-click to run.
I thought maybe $eval or $parse would work but it looks like those will only evaluate expressions within {{}}. What is the best way to execute that ng-click attribute so that when a user hits the enter key, the "this.clickAlert" function is ran and an alert is shown on the screen?
I can't really change any of the code as is above, just looking for the solution within the else statement of the on keydown listener.
I solved it this way:
.on("keydown", (event:JQueryEventObject):void => {
if (event.keyCode === 13) {
if (this.ngDisabled) {
event.preventDefault();
event.stopPropagation();
} else {
// need to execute ng-click here
this.element.trigger("click");
}
}
});
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>
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');
}
}
}
I am writing a search function much like the [cmd+f] function in a browser. I have everything working but I want the enter key on press to cycle through the results through the page. I also have arrow buttons that call the function I wrote and they work. I prevented the default behavior of enter using:
$('form').keydown(function (event) {
if (event.keyCode == 13) {
event.preventDefault();
return false;
}
});
I am using this code to call the function on enter:
$('form').keyup(function (event) {
if (event.keyCode == 13) {
nextSearch();
}
});
It works for the first result but I think it resets the global variable I use to mark the place. The only logical answer I can think of is that pressing enter now refreshes the JavaScript. Is there a way to prevent this?
I use these global variables to keep track:
window.luCurrentNumber = 0;
window.luLastActive = 0;
If I understand you corrected, you the arrow keys and the enter keys to tab instead of performing their default. Here is an example of a function that I use to treat the Enter key as a tab, which I wrote because users kept hitting the enter key and accidentally submitting the page.
//Make enter key is pressed, tab instead of submitting.
$('body').on('keydown', 'input, select', function (e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
Though it's not exactly what you are trying to do, I think it should set you on the right path.
I'm creating a touch application in the "Itunes LP" format which uses html, css and javascript within Itunes to create a "digital LP". The application will have several LP's to explore through a touchscreen.
In fullscreen mode (within Itunes and the LP) you can press the "esc key" to exit the LP and enter "coverflow view" where you can choose another LP to explore. I will have no keyboard or mouse so I need to create a button/link that do one thing when the user clicks on this link and that is to simualte the ESC key being pressed.
So my question is; Is it possible to simulate a keyboard shortcut being pressed using JavaScript in a link? My link would be "Home" and by clicking on this link the browser behaves as the ESC key was pressed.
Any tips on this would be most helpful.
Thanks!
David
ADDED 30/6;
(Part of TuneKit.js for Itunes LP)
/* ==================== Keyboard Navigation ==================== */
TKSpatialNavigationManager.prototype.handleKeydown = function (event) {
var key = event.keyCode;
// check if our controller knows what it's doing and let it take over in case it does
if (this._managedController.wantsToHandleKey(key)) {
// prevent default actions
event.stopPropagation();
event.preventDefault();
// have the controller do what it think is best in this case
this._managedController.keyWasPressed(key);
return;
}
// reset the sound
TKSpatialNavigationManager.soundToPlay = null;
// check we know about this key, otherwise, do nothing
if (TKSpatialNavigationManagerKnownKeys.indexOf(key) == -1) {
return;
}
var navigation = TKNavigationController.sharedNavigation;
// first, check if we're hitting the back button on the home screen, in which case
// we don't want to do anything and let the User Agent do what's right to exit
if (event.keyCode == KEYBOARD_BACKSPACE && navigation.topController === homeController) {
return;
}
// before we go any further, prevent the default action from happening
event.stopPropagation();
event.preventDefault();
// check if we're busy doing other things
if (TKSpatialNavigationManager.busyControllers > 0) {
return;
}
// see if we pressed esc. so we can pop to previous controller
if (event.keyCode == KEYBOARD_BACKSPACE) {
var top_controller = navigation.topController;
if (top_controller !== homeController) {
// at any rate, play the exit sound
TKUtils.playSound(SOUND_EXIT);
// see if the top controller has a custom place to navigate to with the back button
if (top_controller.backButton instanceof Element && top_controller.backButton._navigationData !== undefined) {
navigation.pushController(TKController.resolveController(top_controller.backButton._navigationData.controller));
}
// otherwise, just pop the controller
else {
navigation.popController();
}
}
}
****My script will look like this:****
var albumHelper = {};
albumHelper.playAlbum = function() {
var playlist = bookletController.buildPlaylist(appData.songs);
playlist.play();
};
var event = {};
event.keyCode = function() {
var escapeKeyProxy = TKSpatialNavigationManager.prototype.handleKeydown({'keyCode':27});
document.getElementById('btnExitFullScreen').onclick = escapeKeyProxy;
};
var homeController = new TKController({
id: 'home',
actions : [
{ selector: '.menu > .play', action: albumHelper.playAlbum },
{ selector: '.menu > .linernotes', action: event.keyCode }
],
navigatesTo : [
{ selector: '.menu > .songs', controller: 'songs' },
{ selector: '.menu > .photos', controller: 'photos' },
{ selector: '.menu > .videos', controller: 'videos' },
{ selector: '.menu > .credits', controller: 'credits' }
],
// make the PLAY button be default highlight
highlightedElement : '.menu > .play'
});
So what I want is the .linernotes' image, when clicked, simulate a ESC key being pushed!
This answer assumes there is a JS function that the iTunes LP application uses to exit full-screen.
Though you probably can, you shouldn't have to simulate the event. The Key event you're working with is tied by either an event listener or an event handler to a function (in this case, a function that exits full-screen mode). You should be able to create a button and tie it (by a similar event listener or an event handler) to the same function.
You can't tie it directly, because the key events pass information about which key was pressed, and mouse events don't, so you need to send it through a proxy. Your code might look something like this. In this case, the code that takes in the Key event in the iTunes LP library would be called iTunesLPKeyPressEvent. I have no idea what it's actually called.
var escapeKeyProxy = function() {
iTunesLPKeyPressEvent({'keyCode':27});
}
document.getElementById('btnExitFullScreen').onclick = escapeKeyProxy;
You may need to massage this a bit, but the basic idea should work.
[EDIT]
Based on your update, I'd say that
TKSpatialNavigationManager.prototype._managedController is the object you need to work with and most probably TKSpatialNavigationManager.prototype._managedController.keyWasPressed(key) is the code that captures the escape key. Take a look through the code for addEventListener("keypress",SOME_METHOD,true) (or keyup or keydown) and it will be the SOME_METHOD that's handling the event. That's the method you'll want to hijack. Hopefully it will be in a scope you can easily get to.