Jasmine/jQuery keypress capture - javascript

BACKGROUND
I have a simple form within which the name cannot contain numerics.
So I capture the keypress:
// prevent number from being added in a name
$("#name1__firstname").keypress(function(e) {
rejectCharacterIfNumeric(e);
});
Then use this function to check if numeric, and if so, preventDefault():
// function to disallow numbers added into a text input
function rejectCharacterIfNumeric(e) {
var key = e.which;
key = String.fromCharCode(key);
var regex = /[0-9]|\./;
if (regex.test(key)) {
e.preventDefault();
}
console.log('foo'); // <-- not being fired
};
THE PROBLEM
I need to write a Jasmine test for this but it's not capturing the keypress.
This is what I'm trying:
describe("when text is entered in the input", function(){
var fixture;
beforeEach(function () {
fixture += "<input id='name1__firstname'>";
setFixtures(fixture);
});
it("it should not show if numeric", function(){
var textInput = $('#name1__firstname');
textInput.trigger(
$.Event( 'keypress', { keyCode: 65, which: 65 } ) // letter "a"
);
expect(textInput.val().length).toEqual(1);
});
afterEach(function () {
fixture = "";
fixture = null;
});
})
This test fails as the numbers are inserted into the input Expected 0 to equal 1.
I know the test is not calling rejectCharacterIfNumeric(e) as I've added a console.log() into the function which doesn't fire
QUESTION
How can I pass a keyPress so it fires the rejectCharacterIfNumeric(e) function?

The textInput variable in your spec didn't have the event attached to it:
it("it should not show if numeric", function(){
var textInput = $('#name1__firstname');
textInput.keypress(function(e) {
rejectCharacterIfNumeric(e);
});
textInput.trigger(
$.Event( 'keypress', { keyCode: 65, which: 65 } ) // letter "a"
).val('A');
expect(textInput.val().length).toEqual(1);
});

Related

Filter after the submission of Input Field submitted

I have Input field and Submit Button....When i enter some text to input field it started filtering before i submit (Enter the Submit Button). How can i correct that.
I want to filter after I click the submit button.
$(function() {
var $grid = $('#container');
$grid.isotope({itemSelector: '.item'});
var filters = []; // A convenient bucket for all the filter options,
// just so we don't have to look them up in the DOM every time.
// (a global array is maybe sort of not the most elegant
// way you could deal with this but you get the idea.)
// Search event handlers
$('.quicksearch').on('keyup', function() {
// debounce removed for brevity, but you'd put it here
filters[0] = this.value;
runFilter();
});
$('#filter-select').on('change', function() {
filters[1] = this.value;
runFilter();
});
// and so on if more filters needed
// The filter itself
var runFilter = function() {
$grid.isotope({
filter: function() {
if (filters[0]) {
// at least some search text was entered:
var qsRegex = new RegExp(filters[0], 'gi');
// if the title doesn't match, eliminate it:
if (!$(this).find('.content-title').text().match(qsRegex)) {
return false;
}
}
if (filters[1]) {
// a category was selected; filter out others:
if (!($(this).hasClass(filters[1]))) {
return false;
}
}
// etcetera, for any other filters
// successfully passed all conditions, so:
return true;
}
});
}
});
In your code you have a keyup event. This event type means that every time a key on the keyboard is pressed (and released -- the keyup part), a function will call.
Your code:
// Search event handlers
$('.quicksearch').on('keyup', function() {
// debounce removed for brevity, but you'd put it here
filters[0] = this.value;
runFilter();
});
$('.quicksearch') means that when an element with the class quicksearch...
.on means when an event happens
'keyup' means when a keyboard key is pushed and released
So you have "When the user has the quicksearch selected and they type a letter then run the function". You need to change that to "when the user clicks the button then run the function".
// Search event handlers when button is pushed
$('#id-of-your-button').on('click', function() {
filters[0] = this.value;
runFilter();
});
You can use the ID of the button or the class
if you want to also be able to hit enter
You can look for the keyup on the enter key (similar to what you were doing above). And you can just add both of those blocks to your code.
You need to pass the event information to your function by using function(e). And then you can do a conditional check to see if the key that was pushed and released was the "enter" key -- which is 13 --> if(e.key === 13)
// Search when someone pushes enter in the text field
$(".quicksearch").keyup(function(e){
// Check if the enter key was hit
if(e.key === 13) {
filters[0] = this.value;
runFilter();
}
});
// Search event handlers when button is pushed
$('#id-of-your-button').on('click', function() {
filters[0] = this.value;
runFilter();
});
update based on codepen code
There were a couple of errors in your codepen code. You try to apply the filter, but you don't grab the search box's value to apply. And then you forget to pass that search parameter along to the isotope function.
You can fix this by replacing your quicksearch action to:
// use value of search field to filter
var $quicksearch = $('.bttn').on( 'click',function() {
qsRegex = new RegExp( document.getElementById('quicksearch').value, 'gi' );
$grid.isotope(qsRegex);
});
In your code you use $quicksearch.val(), but you assign the variable $quicksearch as the button.
The complete (corrected) code for the javascript in your codepen is as follows:
// quick search regex
var qsRegex;
var buttonFilter;
// init Isotope
var $grid = $('.grid').isotope({
itemSelector: '.element-item',
layoutMode: 'fitRows',
filter: function() {
var $this = $(this);
var searchResult = qsRegex ? $this.text().match( qsRegex ) : true;
var buttonResult = buttonFilter ? $this.is( buttonFilter ) : true;
return searchResult && buttonResult;
}
});
// bind filter on select change
$('.filters-select').on( 'change', function() {
// get filter value from option value
// var filterValue = this.value;
// use filterFn if matches value
buttonFilter = this.value;
//$grid.isotope({ filter: filterValue });
$grid.isotope();
});
// bind filter on select change
$('.filters-select2').on( 'change', function() {
// get filter value from option value
// var filterValue = this.value;
// use filterFn if matches value
buttonFilter = this.value;
//$grid.isotope({ filter: filterValue });
$grid.isotope();
});
// use value of search field to filter
var $quicksearch = $('.bttn').on( 'click',function() {
qsRegex = new RegExp( document.getElementById('quicksearch').value, 'gi' );
$grid.isotope(qsRegex);
});
// Search when someone pushes enter in the text field
$("#quicksearch").keyup(function(e){
if(e.key === 16 || e.key === 13 || e.key === 'Enter') {
qsRegex = new RegExp( document.getElementById('quicksearch').value, 'gi' );
$grid.isotope(qsRegex);
}
});

Jquery: Executing a function on keypress on google.com

I am trying to capture the search query from google.com when the "enter" key is pressed.
I am using the following code to test that the event is actually being triggered:
$(document).keypress(function(e) {
if(e.which == 13) {
alert('You pressed enter!');
}
});
This does not work when the focus is in the query box, but works fine otherwise I assume this is because an event is not being bubbled up by the auto-complete JS? Any ideas what might be happening, and how I can get the keypress event to fire when the focus is on the query box, which is the case when a query is being entered?
You can try $(window).on('keyup', function() {}); of you can bind the same handler to the search input.
Use "hashchange" event
It is triggered when triggered "auto-complete JS"
$(window).on("hashchange", function() {
var query = getKeywordsFromUrl(document.location.href);
} );
function getKeywordsFromUrl(href) {
var reStr = "google.com/search.*[&?]q=(.*?)(&.*)?$";
var rx = new RegExp(reStr, 'm');
if (rx.test(href)) {
var parts = rx.exec(href);
if (parts[1]) {
var terms = decodeURI(parts[1]).split("+");
return terms;
}
}
return null;
}

How do I prevent user from entering specific characters in a textbox using jQuery?

I have a regular expression that will be matched against the keypress of the user. I'm quite stuck with it.
Here is my current code:
<script type="text/javascript">
$('input.alpha[$id=tb1]').keydown(function (e) {
//var k = e.which;
//var g = e.KeyCode;
var k = $(this).val();
//var c = String.fromCharCode(e.which);
if (k.value.match(/[^a-zA-Z0-9 ]/g)) {
e.preventDefault();
}
});
</script>
The goal here is to prevent the user from typing characters that are inside the regex.
Try using the fromCharCode method:
$(document).ready(function () {
$('#tb1').keydown(function (e) {
var k = String.fromCharCode(e.which);
if (k.match(/[^a-zA-Z0-9]/g))
e.preventDefault();
});
});
You use keypress rather than keydown and prevent the default action.
For example, this prevents typing a w into the text input:
$("#target").keypress(function(e) {
if (e.which === 119) { // 'w'
e.preventDefault();
}
});
Live Copy | Source
Update: If it's applying the regex that's giving you trouble:
$("#target").keypress(function(e) {
if (String.fromCharCode(e.which).match(/[^A-Za-z0-9 ]/)) {
e.preventDefault();
}
});
Live Copy | Source

Invoke a function after right click paste in jQuery

I know we can use bind paste event as below:
$('#id').bind('paste', function(e) {
alert('pasting!')
});
But the problem is, that it will call before the pasted text paste. I want a function to be triggered after the right click -> paste text pasted on the input field, so that I can access the pasted value inside the event handler function.
.change() event also doesn't help. Currently I use .keyup() event, because I need to show the remaining characters count while typing in that input field.
Kind of a hack, but:
$("#id").bind('paste', function(e) {
var ctl = $(this);
setTimeout(function() {
//Do whatever you want to $(ctl) here....
}, 100);
});
Why not use the "input" event?
$("#id").bind('input', function(e) {
var $this = $(this);
console.log($this.val());
});
This will stop user from any pasting, coping or cutting with the keyboard:
$("#myField").keydown(function(event) {
var forbiddenKeys = new Array('c', 'x', 'v');
var keyCode = (event.keyCode) ? event.keyCode : event.which;
var isCtrl;
isCtrl = event.ctrlKey
if (isCtrl) {
for (i = 0; i < forbiddenKeys.length; i++) {
if (forbiddenKeys[i] == String.fromCharCode(keyCode).toLowerCase()) {
return false;
}
}
}
return true;
});
This one will do the same for the mouse events:
$("#myField").bind("cut copy paste",function(event) {
event.preventDefault();
});
Even though the above one will not prevent right clicks, the user will not be able to paste, cut or copy from that field.
To use it after the event, like you wondered on your question, you must use JavaScript Timing Event
setTimeout(function() {
// your code goes here
}, 10);
I had the same issue, I opted to replicate the paste action through javascript and use that output instead:
var getPostPasteText = function (element, pastedData) {
// get the highlighted text (if any) from the element
var selection = getSelection(element);
var selectionStart = selection.start;
var selectionEnd = selection.end;
// figure out what text is to the left and right of the highlighted text (if any)
var oldText = $(element).val();
var leftPiece = oldText.substr(0, selectionStart);
var rightPiece = oldText.substr(selectionEnd, oldText.length);
// compute what the new value of the element will be after the paste
// note behavior of paste is to REPLACE any highlighted text
return leftPiece + pastedData + rightPiece;
};
See IE's document.selection.createRange doesn't include leading or trailing blank lines for source of the getSelection function.
No need to bind :
$(document).on('keyup input', '#myID', function () {
//Do something
});

jQuery: dealing with multiple keypress listeners?

I have a page that needs to do two things at once:
Listen all the time for input from a scanner (which presents as keyboard input), and notice when a string is entered in the right format.
Listen for a user focussing on a particular dropdown, and typing a set of initials - when a set of initials is entered that matches the title attribute of an item in the dropdown, focus on that dropdown.
I can do either of these things separately, but not together. Code:
// Listen for input when userlist is in focus.
$("#userlist").keypress(function (e) {
initials += String.fromCharCode(e.which).toUpperCase();
$(this).find("option").filter(function () {
return $(this).attr("title").toUpperCase().indexOf(initials) === 0;
}).first().attr("selected", true);
// uses timer to check for time between keypresses
return false;
});
// Listen for scanner input all the time.
var input = '',
r1 = /^~{1}$/,
r2 = /^~{1}\d+$/,
r3 = /^~{1}\d+\.$/,
r4 = /^~{1}\d+\.\d+$/,
r5 = /^~{1}\d+\.\d+~{1}$/;
$(window).keypress(function(e) {
// when input matches final regex, do something
}
If I have both, then while the user is focussed on the dropdown, the page does not 'hear' the input from the scanner.
How can I combine the two together to make sure the page reacts to scanner input, even while the user is focussed on the dropdown?
It's because you are overriding the listener on the window object with a listener on the keypress object. I would do something like this:
var input = '',
r1 = /^~{1}$/,
r2 = /^~{1}\d+$/,
r3 = /^~{1}\d+\.$/,
r4 = /^~{1}\d+\.\d+$/,
r5 = /^~{1}\d+\.\d+~{1}$/;
function checkRegex(e) { /* Check */ }
// Listen for input when userlist is in focus.
$("#userlist").keypress(function (e) {
checkRegex(e);
initials += String.fromCharCode(e.which).toUpperCase();
$(this).find("option").filter(function () {
return $(this).attr("title").toUpperCase().indexOf(initials) === 0;
}).first().attr("selected", true);
// uses timer to check for time between keypresses
return false;
});
// Listen for scanner input all the time.
$(window).keypress(function(e) {
checkRegex(e);
}
Wouldn't delegate give you the necessary control? You could then check for the event target and respond accordingly?
ie:
$(window).delegate('keypress', function(e){
if ($(e.target).attr('id') == 'userlist'){
// something
}else{
//something else
}
});
You don't need two handlers. Just have a single handler at the window level and then check which element raised the event:
$(window).keypress(function(e) {
var $target = $(e.target);
if ($target.is("#userlist")) {
initials += String.fromCharCode(e.which).toUpperCase();
$(this).find("option").filter(function () {
return $(this).attr("title").toUpperCase().indexOf(initials) === 0;
}).first().attr("selected", true);
// uses timer to check for time between keypresses
return false;
} else {
// when input matches final regex, do something
}
});
This is probably way more complex than you'd like it to be, but I think it'll fit your purpose.
I tried to make it in the style of a jQuery plugin, and allow you to attach it to any specific object (and customize of it should override bubbling up through the DOM (in the case of your combo box) in addition to allow for windows, etc.
Anyways, try it out and see what you think. I can make modifications if necessary, just need to know what they are.
Working Example: http://www.jsfiddle.net/bradchristie/xSMQd/4/
;(function($){
$.keyListener = function(sel, options){
// avoid scope issues by using base instead of this
var base = this;
// Setup jQuery DOM elements
base.$sel = $(sel);
base.sel = sel;
base.keyPresses = '';
base.validater = null;
// add a reverse reference to the DOM object
base.$sel.data('keyListener', base);
// create an initialization function we can call
base.init = function(){
base.opts = $.extend({}, $.keyListener.defaultOptions, options);
base.$sel.keypress(function(e){
base.keyPresses += String.fromCharCode(e.which);
if (base.validator != null)
clearTimeout(base.validator);
if (base.keyPresses != '')
base.validator = setTimeout(base.validateInput, base.opts.callbackDelay);
if (base.opts.preventDefault)
e.preventDefault();
else if (base.opts.stopPropagation)
e.stopPropagation();
});
};
base.validateInput = function(){
var filter = base.opts.filter;
var reCompare = (typeof(filter)=='object'
? filter.constructor.toString().match(/regexp/i)!==null
: false);
// exception when the input is cleared out
var input = base.sel.constructor.toString().match(/HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement/i);
if (input && (!base.opts.preventDefault && base.$sel.val() == ''))
base.keyPresses = '';
// regular expression match
if (reCompare){
if (base.keyPresses.match(filter))
base.validateSuccess();
else
base.validateFailure();
// traditional string match
}else if (typeof(filter)=='string'){
if (base.keyPresses==filter)
base.validateSuccess();
else
base.validateFailure();
}
// reset string
base.keyPresses = '';
};
base.validateSuccess = function(){
if (typeof(base.opts.success)=='function')
base.opts.success(base.keyPresses);
};
base.validateFailure = function(){
if (typeof(base.opts.failure)=='function')
base.opts.failure(base.keyPresses);
};
// run the initializer
base.init();
};
$.keyListener.defaultOptions = {
// time to wait before triggering callback
// Give it time to accumulate the key presses and send it off
// as a compiled package
callbackDelay: 1000,
// Filter to apply to the input (can be a string match or a regular expression)
filter: /.*/,
// functions to callback when a match has or hasn't been made
success: function(i){},
failure: function(i){},
// would you like this to completely override key input?
preventDefault: false,
// stop it from going up the DOM tree (first object to grab the keypress
// gets it)
stopPropagation: true,
};
$.fn.extend({
keyListener: function(options){
// use return to allow jQuery to chain methods
return this.each(function(){
(new $.keyListener(this, options));
});
}
});
})(jQuery);
$('#listen-scanner,#listen-combo,#listen-text').add(window).keyListener({
filter: /^\d+$/,
success: function(input){
$('#output-scanner').text('Match!: '+input);
},
failure: function(input){
$('#output-scanner').text('No Match: '+input);
},
stopPropagation: true
});
And the HTML I tried it on:
<input type="text" id="listen-scanner" /><span id="output-scanner"></span><br />
<select id="listen-combo">
<option value="AA">Aardvarc</option>
<option value="AB">Abracabra</option>
<option value="AC">Accelerate</option>
<option value="AD">Adult</option>
</select><span id="output-combo"></span>
<textarea id="listen-text"></textarea>

Categories

Resources