button onclick does not fire when its position is changed - javascript

I have a textbox where onchange event adds some element at runtime. Due to this the submit button's position is changed. If user enters something in the textbox and clicks on the button the onclick event does not fire. I suspect its because at the same time the position of the button changes and browser thinks the click happened on page and not on the button.
Is there a way I can handle this situation? I can not move the button above the element which is added at runtime.
I have created a sample jsfiddle: http://jsfiddle.net/WV3Q8/3/
HTML:
<p>Enter something</p>
<input type="text" id="input" onchange="onChange()">
<div id="log"></div>
<button value="Go" style="display:block" type="button" onclick="submit();" id="btn-submit">Submit</button>
JavaScript:
function onChange(){
var value = $('#input').val();
$('#log').append('<p>New value: ' + value + '</p>');
}
function submit(){
alert('value submitted');
}
Edit 1
Test Case (Question is about 2nd test case) Its happening in all browsers (Chrome, IE 10 etc):
Enter something in the textbox and hit tab, p element is added and button's position is moved. Now click on submit button. An alert is shown.
Enter something in the textbox and click on the submit button. p element is added but the alert is not shown.
Edit 2:
I can not use other key events like keyup, keydown or keypress because of obvious reasons (they fire on every keypress).
setimeout too is out of question since there are some radio buttons which are generated at runtime on the onchange event of textbox. Its no wise to click on submit button without showing these radio buttons to user.

For your edit #2 you have to delay the append with setTimeout() method like this:
setTimeout(function(){
$('#log').append('<p>New value: ' + randomVal + '</p>');
},100);
Fiddle

Working Fiddle
A way out is to use onkeypress
<input type="text" id="input" onkeypress="onChange();">
UPDATE
If it is possible for you to use mousedown event, it work's good.
Updated Fiddle

You are missing a return true statement in onChange()
Here is the code on jsfiddle
function onChange(){
var randomVal = Math.floor((Math.random()*100)+1);
$('#log').append('<p>New value: ' + randomVal + '</p>');
return true;
}
function submit(){
alert('value submitted');
}
EDIT: Alternative solution might be calling onChange() inside submit().

I would use setTimeout with keyup event:
var time;
function onChange() {
clearTimeout(time);
time = setTimeout(function() {
var value = $('#input').val();
$('#log').append('<p>New value: ' + value + '</p>');
}, 200);
}
It will append text once user finishes typing.
Demo: http://jsfiddle.net/WV3Q8/8/

This is not good solution but you can trigger the submit function for your case like this:
function onChange(){
var value = $('#input').val();
$('#log').append('<p>New value: ' + value + '</p>');
submit();
}
function submit(){
alert('value submitted');
}
demo

Related

jQuery blur() appears on focus

I want to validate each input of a form on blur() so if user leaves the input box.
$("form#relative_form :input").blur(function() {
var input = $(this).attr('id');
alert("Validate: " + input);
});
It works fine but when i'm in the first input field and hit TAB to get to the next input field,
my script straight validate the second input.
But I want only to validate if i leave the inputs.
JSFiddle
The alert is causing the object to lose focus triggering the blur. Use Console.log() to test instead:
$("form#relative_form :input").blur(function() {
var input = $(this).attr('id'); // This is the jquery object of the input, do what you will
console.log("Validate: " + input);
});
Your code seems to be working fine!!!
But Instead of the alert you must need to use console.log().If you are
using alert then it will continuous call blur function because you are
trying to close the alert box and at that time it will call blur
event.So it's something like circular function.
Instead of:
$("form#relative_form :input").blur(function() {
var input = $(this).attr('id');
alert("Validate: " + input);
});
It should be:
$("form#relative_form :input").blur(function() {
var input = $(this).attr('id');
console.log("Validate: " + input);
});

Prevent function execution twice within two triggered events

I have the following code:
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
The problem with the above is when I click myButton both events are triggered and triggerProcess() is fired twice which is not desired.
I only need triggerProcess() to fire once. How can I do that?
Small demo
You can have a static flag that disables any more triggers once the first trigger has occurred. Might look something like this:
var hasTriggered = false;
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
function triggerProcess () {
// If this process has already been triggered,
// don't execute the function
if (hasTriggered) return;
// Set the flag to signal that we've already triggered
hasTriggered = true;
// ...
}
For resetting the hasTriggered flag, that's entirely up to you and how this program works. Maybe after a certain event occurring in the program you'd want to reenable the ability to trigger this event again — all you'd need to do it set the hasTriggered flag back to true.
You can use the mousedown event, which will fire before the input is blurred, and then check if the input has focus by checking if it's the activeElement, and if it does have focus, don't fire the mousedown event, as the change event will fire instead.
Additionally, if you want a mousedown event to occur when the value hasn't changed, and the change event doesn't fire, you'll need a check for that as well
var myInput = $('#test1'),
myButton = $('#test2'),
i = 0;
myInput.change(function(e) { // this triggers first
$(this).data('prev', this.value);
triggerProcess();
});
myButton.mousedown(function(e) { // this triggers second
var inp = myInput.get(0);
if (document.activeElement !== inp || inp.value === myInput.data('prev'))
triggerProcess();
});
function triggerProcess() {
console.log('triggered : ' + (++i))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="test1">
<br />
<br />
<button id="test2">
Click
</button>
In a fairly typical scenario where you have an input with a button next to ie, eg quick search.
You want to fire when the input changes (ie onblur) but also if the user clicks the button.
In the case where the user changes the input then clicks the button without changing input focus (ie no blur), the change event fires because the text has changed and the click event fires because the button has been clicked.
One option is to debounce the desired event handler.
You can use a plugin or a simple setTimeout/clearTimeout, eg:
$('#inp').change(debounceProcess)
$('#btn').click(debounceProcess);
function debounceProcess() {
if (debounceProcess.timeout != null)
clearTimeout(debounceProcess.timeout);
debounceProcess.timeout = setTimeout(triggerProcess, 100)
}
function triggerProcess() {
console.log('process')
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="inp">
<button id="btn">Click</button>
Use a real <button>BUTTON</button>. If you click on input text, alert is triggered, then once you leave the input text to click anywhere else, that unfocuses the input text which triggers the change event, so now 2 events have been triggered from the text input.
This is an assumption since the code provided is far from sufficient to give a complete and accurate answer. The HTML is needed as well as more jQuery/JavaScript. What is myInput and myButton actually referring to, etc.?
So I bet if you change...
var myButton = $('{whatever this is}'); and <input type='button'>
...TO:
var myButton = $("button"); and <button></button>
...you should no longer have an event trigger twice for an element.
This is assuming that triggerProcess() is a function that does something that doesn't manipulate the event chain or anything else involving events. This is an entirely different ballgame if instead of click() and change() methods you are using .trigger() or triggerHandler(), but it isn't. I'm not certain why such complex answers are derived from a question with very little info...?
BTW, if myInput is a search box and myButton is the button for myInput, as freedomn-m has mentioned, simply remove:
myButton.click(...
Leave myButton as a dummy. The change event is sufficient in that circumstance.
SNIPPET
var xInput = $('input');
var xButton = $('button'); //«———Add
xInput.on('change', alarm);
xInput.on('click', alarm);
xButton.on('click', alarm);
function alarm() {
return alert('Activated')
}
/* For demo it's not required */
[type='text'] {
width: 5ex;
}
b {
font-size: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id='f1' name='f1'>
<input type='text'>
<input type='button' value='BUTTON TYPE'>
<label><b>⇦</b>Remove this button</label>
<button>BUTTON TAG</button>
<label><b>⇦</b>Replace it with this button</label>
</form>

Why doesn't javascript function update DOM on first run

I have a dynamic form in which users can add inputs by clicking a button. This works fine. However when clicking to remove the input the first click does not remove an input. Every click after removes inputs as expected. I can see that it runs the function on first click to remove but nothing is updated in the DOM so the field stays. Here is my HTML:
<button onclick="AddFileField()">Add File</button>
<br />
<br />
<form action="" method="post" enctype="multipart/form-data">
<div id="fileFields"></div>
<br />
<input type="submit" value="Upload" />
</form>
And the associated javascript:
function removeField() {
$('.removeclass').click(function () {
$(this).parent().remove();
});
return false;
}
var FieldCount = 1; //to keep track of text box added
function AddFileField() {
var MaxInputs = 10; //maximum input boxes allowed
var InputsWrapper = $("#fileFields"); //Input boxes wrapper ID
var x = $("#fileFields > div").length + 1; //current text box count
if (x <= MaxInputs) //max input box allowed
{
$(InputsWrapper).append('<div class="fileInp"><label for="file' + FieldCount + '">File:</label><input type="file" name="files" class="inpinl" id="file' + FieldCount + '" />×</div>');
FieldCount++;
}
return false;
}
A fiddle showing issue. To duplicate add a couple fields then click an x. The first click does nothing, then proceeding clicks removes fields. How can I get the first click to remove the field as well?
It's because you are registering your event handler inside of another event handler.
http://jsfiddle.net/3e1ajtvo/11/
I removed your event handler and now, you pass the clicked element as elem into the function itself.
As a matter of fact you don't even really need the function, as long as jquery is exposed (it is in your case).
http://jsfiddle.net/3e1ajtvo/12/
A working fiddle is here
The issue lies in the function:
function removeField() {
$('.removeclass').click(function () {
$(this).parent().remove();
});
return false;
}
When you click the X, this function is called, which adds a click event handler to the X to remove it; however, this event handler is not called until the next time you click it. (This is why clicking X twice works).
In the updated fiddle, you simply pass this to removeField as such:
//HTML
×</div>
//JS
function removeField(me) {
$(me).parent().remove();
return false;
}
The reason for this is because you are using onclick="removeField()".
Lets take a look at your function. When you click on the remove button the following script will run. This script then creates a click handler, that will activate on next click, because when you first clicked on remove the handler was not created
function removeField() {
$('.removeclass').click(function () {
$(this).parent().remove();
});
return false;
}
So you will need to replace this is another function. Since you are using jQuery you can learn to use .on() for dynamically generated elements.
$(document).on('click', '.removeclass', function () {
$(this).parent().remove();
});
http://jsfiddle.net/Spokey/3e1ajtvo/16/
I made your code a bit more modular and changed it to use jQuery more than you were. This is just another way to do it, the other answers are also valid.
http://jsfiddle.net/3e1ajtvo/19/
var fields = {
btnAdd: $('#addField'),
inputWrapper: $('#fileFields'),
maxInputs: 10,
fieldCount: 1,
init: function(){
this.inputWrapper.on('click', '.removeclass', this.removeInput);
this.btnAdd.on('click', this.appendField);
},
removeInput: function(){
//this will refer to the html element you clicked on
$(this).parent().remove();
},
appendField: function(){
//this will refer to the html element you clicked on
if ( fields.inputWrapper.children('div').length <= fields.maxInputs ){
fields.inputWrapper.append('<div class="fileInp"><label for="file' + fields.fieldCount + '">File:</label><input type="file" name="files" class="inpinl" id="file' + fields.fieldCount + '" />×</div>');
fields.fieldCount++;
}
}
};
fields.init();
You're not executing the code to remove the row on the first click, you're just adding the click handler to the link. It works after that because the $('.removeclass').click(... then fires as expected.

Drupal gets into loop when calling input text change event

I'm working with Drupal 7, the problem is that I have an input type text for the quantity of the products with 2 arrows in span by default (widget quantity for the add cart button).
When using the js_injector module for getting the 'change()' event of the input, something weird happens and a loop started changing the value of the input for more or less depending of the clicked arrow.
jQuery(function($) {
$(document).ready(function(){
$('#edit-quantity').bind('change keydown keyup click input submit mouseenter', function (e) {alert('Type: ' + e.type); });
});
});
->This works correctly but doesn't get the arrow-span clicked options:
$('#edit-quantity').bind('keydown keyup click input submit mouseenter',...
->These options create a loop:
$('#edit-quantity').bind('change ...',
OR
$('#edit-quantity').change(function (e) {alert('Type: ' + e.type); });
My point is , Why this .change() event creates such a loop? or better how can I stop it to use the event?
Thank you,
You can use "input" instead of change
$('#textbox').on('input', function() {
// do your stuff
});
Better not to use change on text field. Change is more preferred for radio button, select field, check-box etc...
Hope it helps someone, at the end I just did search for all the possibilities of change. Not only in the input also at the 'buttons' represented with span. I did some little trick and ended up like this:
jQuery(function($) {
function value()
{
if($(this).index()!=0) //Just execute once
{
var price=parseFloat(document.getElementsByClassName('field-item')[0].innerHTML.replace(' €','')).toFixed(2);
var quantity = parseFloat($("#edit-quantity").val());
price *= quantity;
var glbvar = price.toFixed(2).replace('.',',')+' €';
//Set Price
document.getElementsByClassName('field-name-commerce-price')[0].getElementsByClassName('field-item')[0].innerHTML = glbvar ;
}
}
$(document).ready(function(){
//When refreshing the value get lost:
if( parseFloat($("#edit-quantity").val()) != 1) value();
/*For input*/ $("#edit-quantity").bind("propertychange keyup paste input",value);
/*For span*/ $('span').bind('click',value);
});
});

JQuery focus to previous clicked input bug

I have two input fields. The main idea is that whenever you focus to one of the fields, the button click should print a random number inside it.
My problem is that when you just focus on (click on) the first field, then focus on second (or vice versa), the button click prints to both instead of just to the (last) focused field.
You can try to recreate the problem here: http://jsfiddle.net/sQd8t/3/
JS:
$('.family').focus(function(){
var iD = $(this).attr('id');
$("#sets").one('click',function() {
var ra = Math.floor((Math.random()*10)+1);
$('#'+iD).val(ra);
});
});
HTML:
<center class='mid'>
<input type="text" class="family" id="father" />
<br/><br>
<input type="text" class="family" id="mother" />
<br/>
<br/>
<input type='submit' value='Set text' id="sets"/>
</center>
In the "focus" handler, unbind any existing "click" handler:
$('#sets').unbind('click').one('click', function() { ... });
The way you had it, an additional one-shot "click" handler is bound each time a field gets focus, because jQuery lets you bind as many handlers as you like to an event. In other words, calling .one() does not unbind other handlers. When the click actually happens, all handlers are run.
edit — sorry - "unbind" is the old API; now .off() is preferred.
Put the variable iD outside, and separate the functions:
http://jsfiddle.net/sQd8t/8/
This prevents from adding too many events on each input click/focus.
No need to unbind.
var iD;
$('.family').focus(function() {
iD = $(this).attr('id');
});
$("#sets").on('click', function() {
var ra = Math.floor((Math.random() * 10) + 1);
if (iD!="")$('#' + iD).val(ra);
iD = "";
});
See http://jsfiddle.net/sQd8t/11/
$('.family').focus(function(){
$("#sets").attr('data-target',$(this).attr('id'))
});
$("#sets").click(function() {
var target=$(this).attr('data-target');
if(target){
var ra = Math.floor((Math.random()*10)+1);
$('#'+target).val(ra);
}
});
You can create a data-target attribute which contains the field which must be modified.

Categories