This question already has answers here:
How can I get the button that caused the submit from the form submit event?
(22 answers)
Closed 9 years ago.
I'm ajaxifying some forms from a PHP application I didn't write. To do this, I came up with this clever solution:
jQuery("form").submit(function(event) {
// get some values from elements on the page:
var the_form = jQuery(this);
var data = the_form.serialize();
var url = the_form.attr( 'action' );
var button = event.originalEvent.explicitOriginalTarget;
data = data + "&" + button.name + "=" + button.value;
// Send the data using post and put the results in a div
jQuery.post( url, data, function() {
//Do something crazy
});
// stop form from submitting normally
if (event.preventDefault)
{
event.preventDefault();
}
else
{
event.returnValue = false;
}
});
Which works perfectly. I went away rejoicing. The problem is, I inadvertently used a Mozilla/Gecko only property to determine which button was clicked. (event.originalEvent.explicitOriginalTarget) Which means this only works in Firefox. :-(
All of this is necessary because the web app I'm augmenting relies on the button name/value being in the post data to process the form correctly. So, my question in simple terms would be:
What is the best, cross-browser way to determine which button was clicked in jQuery's submit event?
Edit:
And here is my solution.
jQuery("some selector that targets your form").find(":submit").click(function(event) {
// get some values from elements on the page:
var the_form = jQuery(this).parents("form");
var data = the_form.serialize();
var url = the_form.attr( 'action' );
var button = event.target;
data = data + "&" + button.name + "=" + button.value;
// Send the data using post and put the results in a div
jQuery.post( url, data, function() {
//Do something crazy
});
// stop form from submitting normally
if (event.preventDefault)
{
event.preventDefault();
}
else
{
event.returnValue = false;
}
});
See this question: Crossbrowser equivalent of explicitOriginalTarget event parameter
You're going to have to attach the event listeners to the buttons instead of the form to get a good reliable way of determining which one fired the submit.
http://api.jquery.com/event.target/
jquery.event.target should work because it is normalised for most browsers.
jquery.event.currentTarget can be used to retrieve the current item in the event bubbling chain.
Edit--
After some reflection and #greg's suggestion:
I've posted a code snippet on jsfiddle.
Using click handlers to submit the form is problematic beacuse you cannot use submit event handlers for validation (which is the way pretty much any validator plugin does it). Also, when you are not using AJAX to post, disabling submit buttons can have weird effects in some browsers if done in the click event and not the submit event.
The way jQuery.Form solves this is to set up a click handler which stores the clicked button (and then clears it with a small timeout), and use the submit handler to actually send the form contents via AJAX.
Here is a function I used to "ajaxify" my forms with jQuery.
function ajaxifyForm(form, callback)
{
var clicked
form.find("button").click(function()
{
if (clicked != null) clicked.removeAttr("data-clicked")
clicked = $(this)
$(this).attr("data-clicked", 1)
})
form.submit(function(event)
{
var data = {}
var name = ""
form.find(":input").each(function()
{
var input = $(this)
if (!(name = input.attr("name"))) return
switch (input.attr("type"))
{
case "radio":
case "checkbox":
if (input.attr("checked")) data[name] = input.val()
break
case "submit":
if (input.attr("data-clicked")) data[name] = input.val()
break
default:
data[name] = input.val()
}
})
$.ajax({
url: form.attr("action"),
success: function(data)
{
if (typeof callback == "function") callback("success")
},
error: function()
{
if (typeof callback == "function") callback("error")
},
data: data,
type: form.attr("method")
})
return false
})
return form
}
Related
I am doing a Validation for email input
$("#email").on("input",function()
{
email = $(this).val();
const regex_1 = /^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
const regex_2 = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,10})+$/;
var re1 = new RegExp(regex_1);
var re2 = new RegExp(regex_2);
if(re1.test(email)===true && re2.test(email)===true)
{
e.preventDefault();
$.ajax({
url:"Validate.php",
method:"POST",
data:'type=check_email&email='+email,
success:function(data)
{
if(data == 'FAIL')
{
$("#email").addClass("is-invalid");
$("#email").removeClass("is-valid");
$("#email").focus();
}
else
{
$("#email").addClass("is-valid");
$("#email").removeClass("is-invalid");
}
}
});
}
else
{
$("#email").addClass("is-invalid");
$("#email").removeClass("is-valid");
$("#email").focus();
}
$("#email").removeClass("is-invalid");
$("#email").removeClass("is-valid");
});
So my issue is that when the validation through RegEx passes , the AJAX Call is made twice whereas the result from the first success:function(data) itself returns SUCCESS.
Two successive queries for the same instance will increase load on the server unnecessarily.
I personally think my bind is wrong here or that I haven't used e.preventDefault();
But I tried using input focus change keyup (individually as well as multiple binds) but nothing worked, the query still runs twice.
The concept here is that only when the RegEx test returns true then only the ajax is required to run (just once). Why is it running twice here ?
Required : The email(string) should pass both the RegEx tests
The event parameter e in the code is missing.
$("#email").on("input",function(e)
...
...
e.preventDefault();
Edit:
To prevent multiple event firing from the handler, you can return false; From JQuery docs:
Returning false from an event handler will automatically call
event.stopPropagation() and event.preventDefault().
In cases where the event is bound more than once, ensure only one handler is available by using off(). e.g.
$("#email").off('input').on("input",function(e) {
...
(Fiddle: http://jsfiddle.net/qdP3j/)
I have this div:
<div id="addContactList"></div>
I use AJAX and change its innerHTML with something like:
<div id="<%= data[i].id %>">
<img src="<%= picture %>">
<button class="addAsFriend">Add as Friend</button>
</div>
In my JS, I have
$('#addContactList').on('click', '.addAsFriend', function () {
$(this).text('Request sent!');
$(this).attr('disabled','disabled');
});
What happens is that when I click on a button for the first time, I see that the click function ran; "Request sent!" is being shown but it immediately reverts back to the initial button. When I click a second time, it works fine.
I tried using event.stopPropagation and preventDefault but same issue happens.
As stated, it probably comes from the AJAX part:
Basically, I have 3 input fields on a page, and users can enter data in them. If there is data in the fields, they are posted and I use the data to query the database. There is a delay function of 250ms to prevent posting immediately every time a letter is typed.
var addContactsList = document.getElementById('addContactList');
$('#addContactForm').on('keyup change', function () {
var self = this;
// Add a short delay to not post for every letter typed quickly
delay(function() {
var userSearchData = {};
userSearchData.userId = 23;
$.each(['email', 'username', 'fullName'], function (_, el) {
var val = $(self).find('input[name="' + el + '"]').val();
if (val.length >= 3) {
userSearchData[el] = val;
}
});
if ( !isEmpty(userSearchData) ) {
$.post('/post/addContact', { userSearchData: userSearchData }, function (data) {
if (data) {
new EJS({url: '/templates/addAContact.ejs'}).update('addContactList', { data: data })
} else {
addContactsList.innerHTML = '';
}
});
} else {
addContactsList.innerHTML = '';
}
}, 225 );
});
It's because of the "keyup change". Change was being triggered again when clicking elsewhere (the add friend button).
Now though the problem is when people use the autocomplete feature using the mouse, it will not trigger because change isn't there anymore.
As you noticed, the change event fires when your input field loses focus (when you click on the button). You can keep the change event, and check if the change event is firing while the input field is focussed
$('#addContactForm').on('keyup change', function () {
if (!$(document.activeElement).is('input')) return; //add this line
I am still confused about this. Started learning JQuery about a week now and this is what I have:
var IsValidUserName = false;
$(document).ready(function () {
$('#txtUserName').blur(function () {
if ($('#txtUserName').val().match(isNumberLetter) &&
($('#txtUserName').val().length >= 8)) {
$('#userNameError').removeClass("error").addClass("default");
$('#txtUserName').removeClass("alert");
$('#txtUserName + label').removeAttr("id", "lblUserName");
IsValidUserName = true;
}
else {
$('#userNameError').removeClass("default").addClass("error");
$('#txtUserName').addClass("alert");
$('#txtUserName + label').attr("id", "lblUserName");
}
});
});
Lets say I have another function like above, lets say FirstName:
How do I call this on the submit event? The code works as I need it to when the user leaves a field. Not sure how I can also call this code and also use the variable above to prevent submit if the data entered is invalid.
I need to call the validation above if the user clicks the submit button and stop the submission if the IsValidUserName variable is false.
Somethings just need a little push.
Thanks my friends.
Guy
You could always extract it into a function instead of an anonymous function and pass the reference to the object you want to check. This would give you the added benefit of reusing it for other elements.
function validate(ele) {
var valid;
if (ele.val().match(isNumberLetter)) && (ele.val().length >= 8)) {
valid = true;
// update user here.
} else {
valid = false;
// update user here.
}
return valid;
}
$(function(){
$('#firstName').blur(function(){ validate($(this)); });
$('#lastName').blur(function(){ validate($(this)); });
$("yourFrom").submit(function(){
var firstNameIsValid = validate($('#firstName'));
var lastNameIsValid = validate($('#lastName'));
if (!nameIsValid) && (!lastNameIsValid) {
return false;
// User has already been updated
}
});
});
Also, since you are already heavily using javascript for your validation (hope this is convenience and not the only security), you can also disable the submit button entirely until the form meets the proper requirements.
I am having the following JQuery function that is working properly:
$(function () {
$('#accmenu').change(function() {
$(".insightsgraphs div").hide();
$(".insightsoptions input").removeClass("green");
$("#newLikes").one('click', function () {
$.ajax({type:'GET', url: 'newLikes.php', data:$('#ChartsForm').serialize(), success:
function(response) {
var json = response.replace(/"/g,'');
json = "[" + json + "]";
json = json.replace(/'/g,'"');
var myData = JSON.parse(json);
var myChart = new JSChart('dailyNewLikes', 'line');
myChart.setDataArray(myData);
myChart.setAxisNameX('');
myChart.setAxisNameY('');
myChart.setAxisValuesColorX('#FFFFFF');
myChart.setSize(470, 235);
myChart.setTitle('Daily New Likes');
myChart.draw();
}});
return false;
});
$("#unlikes").one('click', function () {
$.ajax({type:'GET', url: 'unlikes.php', data:$('#ChartsForm').serialize(), success:
function(response) {
$("#dailyUnlikes").html(response);
}});
return false;
});
});
$("#newLikes").on('click', function(){
$(this).toggleClass('green');
$('#dailyNewLikes').toggle();
return false;
});
$("#unlikes").on('click', function(){
$(this).toggleClass('green');
$('#dailyUnlikes').toggle();
return false;
});
});
but I want to create a condition: if one of the following two date inputs:
var since = $('#dateoptions input[name="since_date"]').val();
var until = $('#dateoptions input[name="until_date"]').val();
is empty I want to receive an alert and the .one() function to be executed only when the conditions are met. For example when I click on one of the button without the date inputs in place I want to receive an alert like alert("One of the date or both missing") for example and after I choose the dates and press the button again to execute the .one() function like in the above example. I hope I make myself clear enough. I know that I can use something like:
if (until == "" || since == "") {
alert("One of the date or both missing")
} else {}
but my tries so far was no success. Probably I didn't place the condition where it should... Also it is possible also with an alert the inputs to be focused, highlighted or something similar?
EDIT:
Here's a fiddle with it:
http://jsfiddle.net/DanielaVaduva/ueA7R/6/
I replace the ajax call with something else without to modify the flow.
Try checking your values with:
if (until.trim().length === 0 || since.trim().length === 0) {
//TODO here
}
I suggest you that check your name attribute in your inputs and check that it's the same that you use when you are retrieving the values of the inputs.
If it still not working, try some 'debugging' like:
console.log(since);
And check if it is getting your value properly.
UPDATE
I don't know if you wanted this (demo). If your dates are empty, it will not work. AJAX call will not work on JsFiddle, because you are using a .serialize() and it sends the information via URL, as a GET type and you need to send it as POST. It doesn't matter. If you already prepared your server to recieve a GET method, it will work.
Also, I must add that if you want to change color ONLY if the AJAX was success, you must add your change color function as I used on the demo and if you want to check your date every time you want to send information to server, change .one() function into .on() function and remove the function after the AJAX success with:
$('#myimage').click(function() { return false; }); // Adds another click event
$('#myimage').off('click');
$('#myimage').on('click.mynamespace', function() { /* Do stuff */ });
$('#myimage').off('click.mynamespace');
(More info about removing a function here);
I hope this will help you atleast on the way you want to do. Leave a comment if it is not what you wanted.
I'm not sure if I understood the issue exactly but.. you can check this >>
Fiddle Demo
HTML
Add IDs to the date fields like
<input id="until" type="date" name="until_date" value="Until date">
<input id="since" type="date" name="since_date" value="Since date">
And just for highlighting the required dates >>
CSS
.req{
border:2px red solid;
}
.required{
color:red;
font-size: 0.8em;
font-style:italic;
}
jQuery
$(function () {
//removing the highlighting class on change
$('#until').change(function() {
$(this).removeClass('req').next('.required').remove();
});
$('#since').change(function() {
$(this).removeClass('req').next('.required').remove();
});
$('#accmenu').change(function() {
var dSince= $('#since').val();
var dUntil= $('#until').val();
if(dSince=='' || dUntil==''){
alert('You MUST select Both dates!');
$(this).val(0); // Set the menu to the default
//Adding the Highlight and focus
if(dSince==''){
$('#since').addClass('req').after('<span class="required">- required *</span>').focus();}
if(dUntil==''){
$('#until').addClass('req').after('<span class="required">- required *</span>').focus();}
}else{
$(".insightsgraphs div").hide();
$(".insightsoptions input").removeClass("green");
$("#newLikes").one('click', function () {
$("#dailyNewLikes").html('</p>Test daily new likes</p>');
return false;
});
$("#unlikes").one('click', function () {
$("#dailyUnlikes").html('</p>Test daily unlikes</p>');
return false;
});
} //End of the if statement
});
$("#newLikes").on('click', function(){
$(this).toggleClass('green');
$('#dailyNewLikes').toggle();
return false;
});
$("#unlikes").on('click', function(){
$(this).toggleClass('green');
$('#dailyUnlikes').toggle();
return false;
});
});
Thus whenever an option from the accmenu gets selected, it will check for the values of the two DATEs, if both or any is blank, it won't execute the function.
i have jquery code to send request using ajax,.but after success function keypress not firing again this is my code
$(".id_sort").bind('keypress',function(e){
if (e.which == 13){
var index_fix = [];
var index_ori = [];
for (i=0;i < $("tbody tr").length; i++){
index_ori.push(i);
}
$(".id_sort").each(function(){
index_fix.push(Number($(this).val())-1);
});
if (JSON.stringify(index_fix) !== JSON.stringify(index_ori)){
data = { key : 'sort', index : JSON.stringify(index_fix)};
$.ajax({
url : "/ajax/",
data : data,
type : "POST",
cache : false,
success : function (resp){
$(".data").html(resp);
// what should i do here..keypress enter doesn't work in second time
}
});
}
else {
alert("data sama coy");
}
}
});
Check your browser console for JavaScript errors. I suspect that maybe the JavaScript is throwing an error and not running this code anymore after the first keypress.
Is it a problem that if any of the fields of class .id_sort have anything in them besides blank that you'll get NaN when you convert to a number and when you pass the value to the server will it accept NaN for a value?
It sounds to me like the dom node you're binding to may be getting replaced/overwritten by your $(".data").html(resp); call. Binding to events only work on nodes that are already in the dom.
So if that's the case, then you either need to rebind in your success callback after replacing the dom, or you can bind the click event to a higher node. For example: $(".data").on("keypress", ".id_sort", function() { ... });