Sliding down label depending on time difference - javascript

So I have two time fields, timeFrom and timeTo. What I want to do is get a label sliding down if the time difference is equal or greater than 2. But I can't figure out what I'm doing wrong here. Here's my code:
$(document).ready(function() {
$("#timeTo").change(function()) {
var timeTo = $("#timeTo").val();
var timeFrom = $("#timeFrom").val();
var diff = timeTo - timeFrom;
if (diff >= 2){
$("#cost_label").slideDown();
}
else{
$("#cost_label").slideUp();
}
});
$("#cost_label").hide();
$("#timeTo").trigger("change");
});

Try
$(document).ready(function () {
$("#timeTo").on('input', function () {
var timeTo = $("#timeTo").val();
var timeFrom = $("#timeFrom").val();
var diff = parseFloat(timeTo) - parseFloat(timeFrom);
alert(diff);
if (diff >= 2) {
$("#cost_label").slideDown({
complete: function () {
$("#cost_label").hide();
}
});
} else {
$("#cost_label").slideUp({
complete: function () {
$("#cost_label").hide();
}
});
}
});
});
Your label is to hide when the animation completes so it doesn't hide immediately
Strings read as integers, because you can't subtract Strings
on('input') instead of on(change), this is the right way to detect textfield changes
Removed parenthesis after anonymous function declaration, that was a syntax error ;)
You can always debug your problems and use logic to fix these issues.
Somewhat-working Demo

You may not need the + to typecast values and may not need to Math.abs if you're using type="number" inputs with sensible min/max limits.
The 'keyup' event will fire when a key goes from down to up position, so you will not need to unfocus (click or tab away from) the input box. You can also use 'keydown' too, if you're too eager to wait, and don't mind events that fire every 14 milliseconds when the user falls asleep on the keyboard.
Use the $.on instead of the event-named methods so that you can listen for multiple events (as a space separated list) and listen for the event on both inputs (selectors need comma separated list).
$(function(){
$('#cost_label').hide();
$('#timeFrom,#timeTo').on('keyup change', timeChange);
function timeChange(){
var from = +$('#timeFrom').val();
var to = +$('#timeTo').val();
if(Math.abs(to - from) >= 2)
$('#cost_label').slideDown();
else $('#cost_label').slideUp();
}
timeChange();
});
http://jsfiddle.net/LDB5X/ using input type="text"
http://jsfiddle.net/6M5V6/ using input type="number" (might not work in all browsers)
What is this 'input' event? I can't find it in the jquery docs

Related

Why does my counter not work in the field like I would expect

I have implemented a JS counter in my app. I have 2 form fields that my two different counters should work for. A #post_title and a #body-field.
This is my JS:
counter = function() {
var title_value = $('#post_title').val();
var body_value = $('#body-field').val();
if (title_value.length == 0) {
$('#wordCountTitle').html(0);
return;
}
if (body_value.length == 0) {
$('#wordCountBody').html(0);
return;
}
var regex = /\s+/gi;
var wordCountTitle = title_value.trim().replace(regex, ' ').split(' ').length;
var wordCountBody = body_value.trim().replace(regex, ' ').split(' ').length;
$('#wordCountTitle').html(wordCountTitle);
$('#wordCountBody').html(wordCountBody);
};
$(document).on('ready page:load', function () {
$('#count').click(counter);
$('#post_title, #body-field').on('change keydown keypress keyup blur focus', counter);
});
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<label for="title">Title</label>
<textarea id="post_title" placeholder="Enter Title"></textarea>
<span id="wordCountTitle">0</span> words<br/>
<label for="report">Report</label>
<textarea id="body-field"placeholder="Provide all the facts." rows="4">
</textarea><br />
<span id="wordCountBody">0</span> / 150 words
</body>
</html>
The seemingly stray $(document).ready(ready); corresponds to a var ready = function() called earlier in the file that I left out for brevity purposes. But I left the document.ready() call in the order that it appears just incase it could be causing an issue.
So the issue I am having is, whenever you click on the #post_title field and enter words the counter does not update. But as soon as I click on the #body-field and start typing not only does the counter for the #body-field work and start updating immediately, but the counter for the #post_title starts working too and shows the correct amount of words in that field.
What could be causing this?
Edit 1
Just playing with that code snippet I realized that the error exists in another state too. If you just add text to the 2nd field first (i.e. the #body-field) before entering in the title...the counter for the body-field won't increment. It will only update AFTER you start entering a title in the #post_title. So they are both linked somehow.
You should not have the counter function check and perform operations on both fields. The counter function should do exactly the same operation, by utilizing jquery's this keyword inside it, or by taking an event parameter and using that as an alternative, with event.target.
Here's the refactor:
var counter = function(event) {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /\s+/gi;
var $wcField = $(this)[0] === $('#post_title')[0] ? $('#wordCountTitle') : $('#wordCountBody');
if (fieldValue.length === 0) {
$wcField.html('');
return;
}
$wcField.html(wc);
};
$(document).on('ready page:load', function () {
$('#post_title, #body-field').on('change keyup paste', counter);
});
JSBin playground
Also, I am not entirely sure why you are listening to that many events on those textareas, when change keyup paste ought to do it.
the error you're having is because of these 2 blocks of code
if (title_value.length == 0) {
$('#wordCountTitle').html(0);
return;
}
if (body_value.length == 0) {
$('#wordCountBody').html(0);
return;
}
This means that in order for the counters to run, both title and body should have some value. Just remove the return on both and it should work.
EDIT
I think removing both if blocks will also give you the same behavior you want. If you want to have both if blocks, you'll have to separate the counter for the title and body.
EDIT 2
here's a simpler implementation of counter function.
counter = function() {
var title_value = $('#post_title').val();
var body_value = $('#body-field').val();
$('#wordCountTitle').html(title_value.split(' ').length);
$('#wordCountBody').html(body_value.split(' ').length);
}

How to manipulate clipboard data using jquery in chrome, IE 8&9?

This is my jquery code that I am using to truncate the pasted text, so that it doesn't exceed the maxlength of an element. The default behaviour on Chrome is to check this automatically but in IE 8 and 9 it pastes the whole text and doesn't check the maxLength of an element. Please help me to do this. This is my first time asking a question here, so please let me know if I need to provide some more details. Thanks.
<script type="text/javascript">
//var lenGlobal;
var maxLength;
function doKeypress(control) {
maxLength = control.attributes["maxLength"].value;
value = control.value;
if (maxLength && value.length > maxLength - 1) {
event.returnValue = false;
maxLength = parseInt(maxLength);
}
}
//function doBeforePaste(control) {
//maxLength = control.attributes["maxLength"].value;
//if (maxLength) {
// event.returnValue = false;
//var v = control.value;
//lenGlobal = v.length;
// }
// }
$(document).on("focus","input[type=text],textarea",function(e){
var t = e.target;
maxLength = parseInt($(this).attr('maxLength'));
if(!$(t).data("EventListenerSet")){
//get length of field before paste
var keyup = function(){
$(this).data("lastLength",$(this).val().length);
};
$(t).data("lastLength", $(t).val().length);
//catch paste event
var paste = function(){
$(this).data("paste",1);//Opera 11.11+
};
//process modified data, if paste occured
var func = function(){
if($(this).data("paste")){
var dat = this.value.substr($(this).data("lastLength"));
//alert(this.value.substr($(this).data("lastLength")));
// alert(dat.substr(0,4));
$(this).data("paste",0);
//this.value = this.value.substr(0,$(this).data("lastLength"));
$(t).data("lastLength", $(t).val().length);
if (dat == ""){
this.value = $(t).val();
}
else
{
this.value = dat.substr(0,maxLength);
}
}
};
if(window.addEventListener) {
t.addEventListener('keyup', keyup, false);
t.addEventListener('paste', paste, false);
t.addEventListener('input', func, false);
} else{//IE
t.attachEvent('onkeyup', function() {keyup.call(t);});
t.attachEvent('onpaste', function() {paste.call(t);});
t.attachEvent('onpropertychange', function() {func.call(t);});
}
$(t).data("EventListenerSet",1);
}
});
</script>
You could do something like this, mind you this was done in YUI but something simlar can be done for jquery. All you need to do is get the length of the comment that was entered and then truncate the text down the the desired length which in the case of this example is 2000 characters.
comment_text_box.on('valuechange', function(e) {
//Get the comment the user input
var comment_text = e.currentTarget.get('value');
//Get the comment length
var comment_length = comment_text.length;
if(comment_length > 2000){
alert('The comment entered is ' + comment_length + ' characters long and will be truncated to 2000 characters.');
//Truncate the comment
var new_comment = comment_text.substring(0, 2000);
//Set the value of the textarea to truncated comment
e.currentTarget.set('value', new_comment);
}
});
You're putting too much effort into something that is apparently a browser quirk and is mostly beyond your control and could change in the future. In fact, I can't recreate this in IE10 - it behaves just like Chrome for me.
Make sure you are validating the length on the server-side, since it's still possible to get around a field's maxlength when submitting the form input to the server (see this somewhat similar question). That's not to say you shouldn't have some client-side logic to validate the length of the input to enforce the maxlength constraint - I just think you don't need to go to the length you are attempting here to essentially intercept a paste command. Keep it simple - having a basic length validation check in your JavaScript is going to be a lot less messy than what you have here.
Perhaps consider a bit of jQuery like this:
$("#myTextControl").change(function() {
if ($(this).val().length > $(this).attr('maxlength')) {
DisplayLengthError();
}
});
(where DisplayLengthError() is an arbitrary function that triggers some kind of feedback to the user that they have exceeded the maxlength constraint of the field, be it an error label, and alert box, etc.)

autosuggestion box, set focus

Been knocking up a simple suggestion box on an input field.. all working as it should so far except for two issues I can't seem to resolve:
1) when onkeypress event fires, the value of the input box is not correct - it misses off the last character! So for e.g. if you enter 3 chars only first two get carried through. so sometimes suggestions aren't totally accurate!
2) I need to watch out for users pressing the arrow down key, and then set focus to the first list item in the suggestion box! Can't seem to get this working though!
Have included code for you to look at! Any suggestions welcomed.. However I don't really want to use a plugin seeing as I have this 95% done already..
Here is the jsfiddle link!
http://jsfiddle.net/beardedSi/kr4Cq/
Note - I just noticed that in the fiddle verison as I have put dummy array in the code it is no longer matching suggestions - but this doesn't matter, it works fine in my working code!
work = true;
function finish() {
work = true;
}
var autoComp = $('.autoComp');
var skillInput = $('.new-skills input');
$('.new-skills input').keypress(function (e) {
var param = $(skillInput).val();
if (param.length > 0) {
$.getJSON('/recruiter/home/GetAutocompleteSkills?term=' + param, function (data) {
$(autoComp).slideDown().empty();
var items = [];
$.each(data, function (key, val) {
items.push('<li>' + val + '</li>');
});
$(autoComp).append(items.join(''));
$('.base-wrapper a').not('.button').click(function (e) {
work = false;
e.preventDefault();
$(skillInput).val($(this).text());
$(autoComp).empty().slideUp(500, finish);
});
});
}
});
$(skillInput).keydown(function (e) {
if (e.keyCode == 40) {
console.log("down");
$('.autoComp li:first:child').focus();
}
});
$('.new-skills input').blur(function () {
if (work == true)
$(autoComp).slideUp();
});

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>

Problem invoking a function on change event

I am trying to invoke an ajax call as soon as my input fields length is 15 (for now I have just put in an alert box in place of .ajax{ }), but the alert box is not firing up until I click somewhere on the screen after input field is filled with 15 characters.
what am I doing wrong here?
$("#serialCode").change(function () {
var d = $("#serialCode").val();
if (d.length == 15) {
var $code = d.substring(0, 9);
alert('Serial code ' + $code);
}
$(this).val("");
});
You'll likely want to use keypress instead of keyup or keydown, as those won't be called for subsequent characters if someone holds a key down.
$("#serialCode").keypress(function () {
var d = $("#serialCode").val();
if (d.length == 15) {
var $code = d.substring(0, 9);
alert('Serial code ' + $code);
}
$(this).val("");
});
I wrote a blog post earlier today on why onkeyup isn't a great idea for detecting user input. The better option is to either use onkeydown with a 0ms timer, or a combination of the newer HTML 5 event oninput for standards compliant browsers and onpropertychange in Internet Explorer.
These two events will handle other forms of input such as cut, paste, undo, redo, drag and drop, and even changes made by a native spell checker.
Something like this should work for you:
// Check for which event we need to bind to, onpropertychange or oninput
var evt = "onpropertychange" in document.body ? "propertychange" : "input";
$("#serialCode").bind(evt, function (event) {
// For the onpropertychange event, check that the value property changed
if (evt == "propertychange" && event.propertyName != "value")
return;
var d = $("#serialCode").val();
if (d.length == 15) {
var $code = d.substring(0, 9);
alert('Serial code ' + $code);
}
$(this).val("");
});
Note that if you need to support older browsers, you'll need to use some form of event detection to see if these events are available and if not, fall back to the keydown with timer method.
The change event doesn't fire until you lose focus on the input.
Try using keyup instead:
$("#serialCode").keyup(function () {
var d = this.value;
if (d.length == 15) {
var $code = d.substring(0, 9);
alert('Serial code ' + $code);
}
// this.value = '';
});
You should note that people can get around this by using the GUI to paste text into the input, so you may want to add the same functionality on change as well.
$("#serialCode").bind('keyup keydown change', function () {
Because there are multiple events, you should have some sort of flag that is set when the AJAX request is sent, so you're not sending it multiple times.
i experienced issues with the jQuery ajax interface. those issues disappeared when i decided to just use to javascript only interace.
see this link hosted at IBM. once you read this you will never again have a question with how ajax does or should function.

Categories

Resources