Delegating change event on input field - javascript

I'm trying to fire a function whenever the value of an input field changes. The input field is in a lightbox so I have to delegate the event:
var validateDonation = function(elem) {
var msg,
value = elem.value;
if (value == '') { msg = 'Please enter an amount'; }
else if(parseInt(value, 10) < 1) { msg = 'Please enter an amount greater than 1'; }
else if(parseInt(value, 10) > 100) { msg = 'Please enter an amount less than 100'; }
else { msg = ''; }
if(msg != '') {
console.log(msg);
}
}
and
$('body').delegate('#donation_amount', 'change', function(event) {
validateDonation(this);
});
If I use keyup instead of change the console log works just fine. But not on change. Why?

https://msdn.microsoft.com/en-us/library/ms536912(v=vs.85).aspx
onchange: This event is fired when the contents are committed and not while the value is changing. For example, on a text box, this event is not fired while the user is typing, but rather when the user commits the change by leaving the text box that has focus. In addition, this event is executed before the code specified by onblur when the control is also losing the focus.
If you want the change to be instantly updated then you would want to use the oninput event
oninput: The DOM input event is fired synchronously when the value of an <input> or <textarea> element is changed. Additionally, it fires on contenteditable editors when its contents are changed.
For IE less than IE9 i believe you need to use the onpropertychange event as well as oninput to accommodate modern browsers.
Here is a fiddle to show you the event fires immediately
http://jsfiddle.net/SeanWessell/9jfkcapp/
Try this...
$('body').delegate('#donation_amount', 'input propertychange', function (event) {
validateDonation(this);
});

Related

Triggered keypress events not being captured?

I'm capturing input from a barcode scanner (which acts like keyboard input) and it works great, but I don't have access to a barcode scanner at the moment and need to test my code, so I need to simulate the barcode scanner (keyboard) input.
I thought triggering keypress events for each character would work, but it doesn't. Here's my test code:
var barcodeScannerTimer;
var barcodeString = '';
// capture barcode scanner input
$('body').on('keypress', function (e) {
barcodeString = barcodeString + String.fromCharCode(e.charCode);
clearTimeout(barcodeScannerTimer);
barcodeScannerTimer = setTimeout(function () {
processBarcode();
}, 300);
});
function processBarcode() {
console.log('inside processBarcode with barcodeString "' + barcodeString + '"');
if (!isNaN(barcodeString) && barcodeString != '') { // #todo this check is lame. improve.
alert('ready to process barcode: ' + barcodeString);
} else {
alert('barcode is invalid: ' + barcodeString);
}
barcodeString = ''; // reset
}
window.simulateBarcodeScan = function() {
// simulate a barcode being scanned
var barcode = '9781623411435';
for (var i = 0; i < barcode.length; i++) {
var e = jQuery.Event("keypress");
e.which = barcode[i].charCodeAt(0);
$("body").focus().trigger(e);
}
}
JSFIDDLE
If you type in a number quickly (like 1234), you'll see the input is captured fine. However, click the button to run my test code, and the input is not captured. The event is triggered because an alert box pops up, but barcodeString is empty!
Why isn't this working? Should I be triggering some event other than keypress?
The handler is reading the charCode but you are only setting which on the event. Set charCode, or read from which. https://jsfiddle.net/mendesjuan/bzfeuezv/1/
barcodeString = barcodeString + String.fromCharCode(e.which);
Firing Synthetic events
This is a reminder that firing synthetic events is tricky business and typically requires you to have intimate knowledge of the handlers (which is bad) so that you don't have to construct a full event object. Also, beware that not all events triggered by jQuery will actually trigger the native events and cause its default action to apply.
Simply put, triggering keypress does not actually type a character into a text field or fires event handlers not set with jQuery.
document.querySelector('input').addEventListener('keypress', function() {
console.log('standard input key press handler');
});
var e = jQuery.Event("keypress");
e.which = "a".charCodeAt(0);
$('input').keypress(function(){
console.log('jQuery input key press handler');
}).trigger('keypress', e);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input value="yo" />

Changing input value inside "input" event handler prevents "change" event firing in Chrome and IE (but not in Firefox)

In the following code I have "input" event handler that changes the value of the input as the user types. I also have "change" event handler to keep track of any changes made to this field. For some reason "change" event doesn't fire in Chrome and IE when the user leaves the field. Why is that and how to make it work in all major browsers?
Also note that it's not acceptable to trigger "change" event manually every time "input" event fires.
EDIT: "change" event seems to fire in Chrome only if transform function does not change the resulting string in any way. So if I type lower case letters and focus out after every character, "change" fires only for indexes 0, 2, 4 ...
Link to fiddle: http://jsfiddle.net/3hqxx2pr/
function transform(s) {
var r = "";
for (var i = 0; i < s.length; i++) {
r += i & 1 ? s[i].toUpperCase() : s[i];
}
return r;
}
$(document).ready(function(){
$("#in").on("change", function() {
console.log("changed"); // works only in ff
});
$("#in").on("input propertychange", function() {
$("#in").val(transform($("#in").val()));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<input id="in"/>
Trigger change yourself
$("#in").val(transform($("#in").val())).change();
or
$("#in").val(transform($("#in").val())).trigger("change");
Based on a edit and restriction you made:
$("#in").on("input propertychange", function() {
var inp = $(this);
var orgVal = inp.val();
var transVal = transform(orgVal);
if (orgVal !== transVal) {
inp.val(transVal).trigger("change");
}
});

Prevent From Writing on TextArea using Bind Event "input propertychange"

I am handling the content inside a textarea using binding a function to the event "input propertychange"
Like this:
$('#textarea').bind('input propertychange', function () {
var textarea = document.getElementById('textarea');
window.lastLineWriting = textarea.value.substr(0, textarea.value.length).split("\n").length;
var writingOnLine = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
if (writingOnLine < window.lastLineWriting) {
//dont write on textarea
}
});
I don't know how to prevent the char typed by the user's keyboard to appear on the textarea... Inside that if I want to prevent the text to be inserted on textarea..
How can I do this?
you could easily stop the user from typing with this code, using jQuery:
$('textarea').bind('keypress', function (e) {
e.preventDefault();
return false;
});
NOTE:
this code will prevent the user from typing in all the textareas, to bind it specifically to one or some selected elements, you must change the selector to the desired elements.
var editable = false // Your Condition
if(editable != "true"){
$("#textarea" ).attr("disabled",true);
}

Multiple event listener in Javascript

How to add multiple event listeners in the same initialization?
For example:
<input type="text" id="text">
<button id="button_click">Search</button>
JavaScript:
var myElement = document.getElementById('button_click');
myElement.addEventListener('click', myFunc());
This is working correctly however I would like to have another event listener for this input filed in the same call if that is possible, so when user clicks enter or presses the button it triggers the same event listener.
Just one note. User needs to be focused on the input field to trigger an "enter" event.
Just bind your function to 2 listeners, each one of the wished element:
document.getElementById('button_click').addEventListener('click', myFunc);
document.getElementById('text').addEventListener('keyup', keyupFunc);
where the new function test if the user pressed enter and then execute the other function :
function keyupFunc(evt) {
if(evt.keyCode === 13) // keycode for return
myFunc();
}
Working jsFiddle : http://jsfiddle.net/cG7HW/
Try this:
function addMultipleEvents(elements, events){
var tokens = events.split(" ");
if(tokens.length == elements.length){
for(var i = 0; i< tokens.length; i++){
elements[i].addEventListener(tokens[i], (e.which == 13 || e.which == 48)?myFunc:); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([textObj,btnObj], 'click keyup');
UPDATE:
function addMultipleEvents(elements, events) {
var tokens = events.split(" ");
if (tokens.length == elements.length) {
for (var i = 0; i < tokens.length; i++) {
elements[i].addEventListener(tokens[i], myFunc); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([btnObj, textObj], 'click keyup');
function myFunc(e) {
if (e.which == 13 || e.which == 1) {
alert("hello");
}
}
Working Fiddle
I think the best way to do this is by using for loops.
const events = ["click", "mouseover"]
for (i in events) {
document.getElementById("button_click").addEventListener(events[i], () => myFunc())
}
The code above loops through every events inside an array and adds it to the button.
Yeah this is a good question and can apply to other scenarios. You have a form and a user will have input text field, a radio box, a select option. So now you want the submit button to go from disabled to enabled. You decide to add an event listener to check if fieldA and fieldB and fieldC is first to enable submit button.
If you use event listener on Keyup", and all your fields are valid, the submit button will become enabled only if the last field is a text field because the event will only be triggered when you let go the key. This means it will not trigger if the radio box or select option is selected with your mouse. We must not rely in the order the fields are filled for the logic to work. Again, If you use "click", it sucks, because user will have to click somewhere on page in order for the event listener to fire and run the logic. So i think we'll need an event lister on mouseup, keyup and change for this example below. I assume you made all your validations and variables for the form fields already. We need a function with parameters of multiple events names as a string, the element we want to target (document, or button or form), and a custom function that contains our logic.
// Create function that takes parameters of multiple event listeners, an element to target, and a function to execute logic
function enableTheSubmitButton(element, eventNamesString, customFunction) {
eventNamesString.split(' ').forEach(e => element.addEventListener(e, listener, false));
}
// Call the above function and loop through the three event names inside the string, then invoke each event name to your customFunction, you can add more events or change the event names maybe mousedown, keyup etc.
enableSubmitButton(document, 'keyup mouseup change', function(){
// The logic inside your customFunction
if (isNameValid && isLocationValid && isProjectValid){
publishButton.disabled = false;
} else {
publishButton.disabled = true;
// Do more stuff like: "Hey your fields are not valid."
}
});
// The isNameValid isLocationValid, isProjectValid are coming from your previous validation Javascript for perhaps a select field, radio buttons, and text fields. I am adding it as an example, they have to be equal to true.
// The publishButton is a variable to target the form submit button of which you want enabled or disabled based one weather the form fields are valid or not.
// For example: const publishButton = document.getElementById("publish");

Trigger event of auto popup list selection via javascript

I have previously entered value 1111, 1222, and 1333 into a HTML text input. Now if I enter 1 to the text input, it should popup a list with value 1111, 1222, and 1333 as available options. How do you trigger an event when any one of these options is selected?
I have a javascript function that performs a calculation on values entered into the text input via "onkeyup" event. This works very well if the user just enter value via keyboard. However, it does not work if the user is selecting a previously entered value from the auto popup list.
I know we can turn off the auto popup list by adding autocomplete="off" to the form/text input. But is there any solution to make it work with the auto popup list? I have tried all available event options including "onchange", but none of those works.
The HTML code is very simple:
<input id="elem_id_1" name="output" type="text" value="0" onkeyup="update();"/>
The js function is very simple too:
function update() {
var a = $('elem_id_1').value;
$('elem_id_2').value = a / 100;
}
Have you tried the onchange event? I'm not sure if it fires for auto-complete selection, but you could also try the onpropertychange event and check for the value property:
textInput.onpropertychange = function ()
{
if (event.propertyName == "value")
doCalculation();
}
This would also work on right-click->paste or right-click->cut, which wouldn't fire your calculation using your current method.
EDIT
It looks like you might have to use a combination of events and timers. Set an interval on focus of the edit and clear it on blur. I'd also use the onpropertychange for IE to make it more efficient and keep the keyup event to make it rather quick too.
//- If it's IE, use the more efficient onpropertychange event
if (window.navigator.appName == "Microsoft Internet Explorer")
{
textInput.onpropertychange = function ()
{
if (event.propertyName == "value")
doCalculation();
}
}
else
{
var valueCheck, lastValue = "";
textInput.onkeyup = function ()
{
doCalculation();
}
textInput.onfocus = function ()
{
valueCheck = window.setInterval(function ()
{
// Check the previous value against (and set to) the new value
if (lastValue != (lastValue = textInput.value))
doCalculation();
}, 100);
}
textInput.onblur = function ()
{
window.clearInterval(valueCheck);
}
}
If your calculation routine is tiny (like a simple mathematical equation), I would just leave out the previous value check and run the calculation every 100ms.

Categories