I have a form like the following:
The forms id is 'filter' and I have a jquery onclick function which runs code by using the following line:
$(document).on('click', '#filter', function(){
//on click do the following
This works perfectly. However, I have now added a checkbox to the form. The rest of the form continues to work perfectly but the checkboxes are 'uncheckable'! (if they are set to be pre-checked they stay pre-checked, if they are set to be unchecked they stay unchecked).
The only thing I can think is that the jquery on click function is overriding the checking of the checkboxes. Would this be the case? I can rectify the problem by using blur rather than click but ideally the code would run on click, and in any case id like to understand what is going on! Any ideas?
EDIT
This is the contents of the click handler:
$(document).on('click', '#filter', function(){
//on click do the following
var formData = $(this).serialize(); //put the form names and values into an array called formdata
$.get('filtertest.php',formData,processData); //jquery ajax call
function processData(data){
if(data==1){
$('#content').html('<h2>There is ' + data + ' property available!</h2>');
$('#linky').show();
}
else if(data==0){
$('#content').html('<h2>There are no properties available, please expand your search options.</h2>');
$('#linky').hide();
}
else{
$('#content').html('<h2>There are ' + data + ' properties available!</h2>');
$('#linky').show();
}
}//end processData
return false; //stops the page redirect as per normal operation
});//end submit
Basically the click function looks up matching details from the form in a database and returns the number of matching rows to put in the processdata function
This line is preventing the checkbox from checking:
return false; //stops the page redirect as per normal operation
Using return false will stop event propagation AND prevent the default behavior. The default behavior of a checkbox is to check/uncheck itself when clicked. You might be able to fix this by changing it to:
e.stopPropagation();
This should let the default behavior continue, without propagating any other events that will fire afterwards.
Or you can just take it out if it is no longer needed (based on your comment).
Related
What I want to achieve is to track form submits.
But because of the many variations that we use for the submit button I want to change my current code:
$(document).on('click','input[type="submit"], button[type="submit"]',function(){
to something that is universal. And I believe the best approach is the $("form")-annotation.
The problem is that for example if a form has an ajax script on it, it gets blocked by my additional script code.
Basically what I want to achieve is to have both worlds.
So the first one is what the website currently has (not every websites though):
$("form").submit(function () {
// ....do something, maybe ajax submit of the form.....
});
and my additional that I want to add without editing any current scripts already found in the website:
$("form").submit(function () {
$.getJSON("....");
});
The solution for me should be that the second script (the additional) will not interfere with any other form scripts.
AN IDEA
To add a class by using jQuery addClass to the forms of current page.
What is a solution for this?
I created a little Snippet to demonstrate the issue:
$(document).ready(function() {
// Registering form-submission as the first would be a possibility
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My first callback is executing');
// Do some stuff here, but don't mess with the event-object
// (like preventing default or stopping the event-chain)
});
// Then afterwards everything else that *might* catch the event
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My second callback is executing');
// Usually some Ajax-Handler-Callback, that handles sending the form,
// will preventDefault() and stopImmediatePropagation() - that is why
// your general first listener must be registered before any of these callbacks
console.warn('Second callback stops the event from bubbling/propagating');
e.stopImmediatePropagation();
e.preventDefault();
});
// This will never happen
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My third callback will never execute');
});
// Using a delegated event-listener with `useCapture` lets this execute first
document.addEventListener('submit', function(e) {
console.info('Capturing the event natively');
}, true);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>My Website with a multi-handled form</h1>
<form class="" action="" method="post">
<input type="text" name="test" value="">
<button type="submit" name="button">Send</button>
</form>
Output of the Snippet, when submitting the form:
Capturing the event natively
<form class action method="post">…</form>
My first callback is executing
<form class action method="post">…</form>
My second callback is executing
Second callback stops the event from bubbling/propagating
What did just happened?
By pressing the submit-button, our form emits the submit-event. The Browser starts with the event-propagation in a specified event-order. There are two phases of event-propagation: event-capturing and event-bubbling.
Now our first called event-listener is the one with the useCapture-directive.
This is during the capture-phase of the event-propagation.
Explanation for useCapture taken from MDN:
capture: A Boolean that indicates that events of this type will be
dispatched to the registered listener before being dispatched to any
EventTarget beneath it in the DOM tree.
When done, the Browser starts with the bubbling-phase of the event-propagation.
This is where all $('element').on() and element.addEventListener() (without the useCapture option) registered listeners are called in their appearing order.
During this phase our second listener is not only preventing default (not submitting the form the standard-way), but also stopping the event-propagation by calling e.stopImmediatePropagation().
After that the event-chain/event-propagation stops immediately.
That is why our third listener will never execute.
On a side note: When using jQuery and exiting an event-callback with
return false, jQuery will execute e.preventDefault() and
e.stopPropagation() automatically.
See: http://api.jquery.com/on/
Conclusion
You basically have two possibilities for your scenario:
Register your default general event-listener before anything else (first event-registration in Snippet).
Register an event-listener during the capture-phase, to capture the event and handle things before the other listeners from the bubbling-phase get called (last event-registration in Snippet).
With both methods you should be able to do your stuff without interfering with other event-listeners.
Use this:
$(document).on("submit", "form", function (e){
Complete example:
<form id="form1"><input type="text" /><input type="submit" /></form>
<form id="form2"><input type="text" /><input type="submit" /></form>
Js:
$(document).on("submit", "form", function (e) {
var oForm = $(this);
var formId = oForm.attr("id");
var firstValue = oForm.find("input").first().val();
alert("Form '" + formId + " is being submitted, value of first input is: " + firstValue);
return false;
})
[JS fiddle]: http://jsfiddle.net/pZ3Jn/
What I want to achieve is to track form submits.
Why not just use $(document).on('submit', 'form', function(){});?
It will be triggered on every form submit, no matter how it is being submitted.
$(document).ready(function() {
// Some already existing event handler
$('#bir').on('submit', function(e) {
console.log($(this).attr('id'));
e.preventDefault();
});
// Your universal form event handler
$(document).on('submit', 'form', function(e) {
console.log('Additional functionality for: ' + $(this).attr('id'));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="bir">
<input type="submit" />
</form>
<form id="ikki">
<input type="submit" />
</form>
I've ran into this issue a few times before and my solution was to capture all form nodes and associate them with a special action . This may not be practical but is a possible solution for you also .
Example
//Getting all form elements
var formNodes = document.getElementsByTagName('form');
//loop through nodelist and add submit event and special class to each.
for(var i = 0; i < formNodes.length; i++){
formNodes[i].addEventListener('submit' , registerAction)
formNodes[i].className += "form-" + i;
}
/*This function captures the submitted form and determines
the action to carry out based off class name .
e.preventDefault will stop page from reloading in case of
making ajax requests.
*/
function registerAction(e){
e.preventDefault();
var formTarget = $(e.target).attr('class');
switch(formTarget){
case "form-0" :
// Do something ...
break;
case "form-1" :
// Do something else...
break;
default:
break;
}
return false;
}
Keep in mind that the logic inside registerAction can be alter to fit your needs
in this situation I used "case statement" because I feel it makes the most sense .
This is not perfect but I hope it gives you an idea..
The problem is that for example if a form has an ajax script on it, it
gets blocked by my additional script code.
No, it doesn't. You can bind many handlers on one element.
For rare cases, see the other suggestions, but If I got you right, your basic assumption was that binding a handler on an element cancel the previous one. Well, it doesn't.
I'm new to Javascript and JQuery, and I'm implementing a warning to users that displays when they have made unsaved changes to a form's input/select/textarea elements if they navigate away from a page. I currently have the following which works fine when they leave a static form page:
/*
* Warn users when leaving a page with unsaved content, watches elements: (input, textarea, select) unless
* they are tagged with the "noWarning" class
*/
$(document).ready(function() {
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
window.onbeforeunload = function(e) {
return 'You have unsaved changes';
};
});
});
The only page where it does not work, is in our main editing page. This page, unlike the others, has multiple tabs for editing different aspects of an item, which when clicked, trigger an AJAX call which replaces the content div with the appropriate form for editing the different aspect.
No warning dialog is displayed when a user clicks on a tab though, so any unsaved changes to the input are lost.
My intuition is that because the url is not changing, onBeforeUnload() is not executing. So I would have to check for any changes directly in the function which handles the AJAX call for replacing the form when a tab is clicked:
function clickedTabbedMenu() {
// This function replaces the content div with a new div and form
}
So my question is, how do I go about checking if any changes have been made to the elements in the current form before I replace the content div with another??? Can I directly call the "change" event listener for a true/false??? Or perhaps a different approach to handle this page's warning messages?
Any help is appreciated
Attach a change event handler to all the elements of the form. Have a variable outside the handler's scope dirty (or even a data on the form element) be set to false when a form is loaded, and true on every change event. Then, before replacing the form, check if dirty.
This would also be a good strategy for your non-AJAX pages as well - instead of setting the whole onBeforeUnload each time an element changes, just set onBeforeUnload once, and check if dirty inside it. This makes handling your AJAX and non-AJAX pages very similar.
EDIT: Untested because it's late and I need bed, but basically:
$(document).ready(function() {
var dirty = false;
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
dirty = true;
});
function checkDirty() {
if (dirty) {
alert('You have unsaved changes');
return false;
}
return true;
}
// for non-AJAX pages
window.onbeforeunload = function(e) {
return checkDirty();
};
// for AJAX pages
$('.ajax_navigation_tab').on('click', function() {
if (!checkDirty()) {
// do the ajax thing
dirty = false;
}
});
});
I would try checking for and calling window.onbeforeunload() in your ajax script.
If it exists and returns a string, use it as an error message and halt the operation :)
I have a input form with Jquery & PHP what I am trying to archive is if a user makes any changes to the form and they try to navigate away from the page A popup message comes up saying if they want to exit and discard changes or stay and save the changes first?
How could I archive this thought I did it but all my current one is doing is checking if the fields have data in them but i'm making use of the value='' feature in HTML to get the current settings in the database.
Only run this function if submit has not been pressed yet.
1 Create a flag that specifies whether something was changed:
var changes = false;
2 Bind an event listener to every single input and textarea that sets changes to true:
$('textarea,input').on('keypress change input', function() {
changes = true;
});
3 Bind an event listener to onsubmit that sets changes to false:
$('form').on('submit', function () {
changes = false;
});
4 Bind an event listener to onbeforeunload that returns the question if there are changes:
$(window).on('beforeunload', function () {
if (changes) return "Do you really want to leave?";
});
Demo on JSFiddle: http://jsfiddle.net/TimWolla/VYKeu/
I have a list of radio buttons that I can toggle "yes" or "no" to using Javascript.
$(document).ready(function(){
$('#select-all').click(function(){
$('#notifications .notif-radio').each(function(){
$('input[type="radio"]', this).eq(0).attr('checked', true);
$('input[type="radio"]', this).eq(1).attr('checked', false);
});
});
$('#deselect-all').click(function(){
$('#notifications .notif-radio').each(function(){
$('input[type="radio"]', this).eq(0).attr('checked', false);
$('input[type="radio"]', this).eq(1).attr('checked', true);
});
});
});
this works just fine. Now I have a separate piece of code that detects when a user has changed something, and asks them if they want to leave the page.
var stay_on_page;
window.onbeforeunload = confirm_exit;
$('.container form input[TYPE="SUBMIT"]').click(function(){
stay_on_page = false;
});
$('#wrapper #content .container.edit-user form').change(function(){
stay_on_page = true;
});
function confirm_exit()
{
if(stay_on_page){ return "Are you sure you want to navigate away without saving changes?"; }
}
The problem is that if the user uses the first piece of functionality to toggle all radio buttons one way or another. The JS detecting form changes doesn't see that the form was changed. I have tried using .live, but to no avail. Anyone have any ideas?
I do something similar to this by adding change() (or whatever's appropriate, click() in your case I suppose) event handlers which set either a visible or hidden field value, then check that value as part of your onbeforeunload function.
So, my on before unload looks like:
window.onbeforeunload = function () {
if ($('#dirtymark').length) {
return "You have unsaved changes.";
}
};
And, or course, dirtymark is added to the page (a red asterisk near the Save button), when the page becomes dirty.
The client is making a request to the server.
I need to take part of that request, and make the form button work with Ajax.
This piece of code works perfectly for links:
var pagination_render = function() {
var pagination = $('.pagination a');
pagination.each(function() {
$(this).click(function(event) {
load_server(this.href, '.houseindex');
return false;
});
});
};
pagination_render();
I tried numerous things for making the Ajax button work, and this is one of the tries:
var contact_user = function () {
$('.expanded').find('#submit').each(function() {
$(this).unbind('click');
});
$('.expanded').each(function() {
$(this).find('#submit').click(function(event) {
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
});
}
Whenever there is a successful Ajax call, it goes through all of the expanded items, and then binds a click event.
Now, sometimes this code works, and sometimes it doesn't.. When it doesn't work, it disables other events (toggle links) I have set up.
It seems as if I need to wait a few ms for it to load the component into the DOM.. Do I?
So I get that when you call contact_user you:
First unbind any previous binded click events from the submit button. I see one possible problem there and is that you are looking for an id of #submit. You should only have one id in a single page. Therefore you only need to use $('#submit').each(...) or if you have several submit buttons in the page either use a class if there are several submit buttons inside an .expanded item or just use $('.expanded :submit')
Adding a custom event when clicking the submit button. Same thing, you can simplify this by $('.expanded :submit') or if you truly only have one button with an id of submit (quite confusing). Go with $('#submit').
In conclusion:
var contact_user = function(){
$('.expanded :submit').unbind('click');
$('.expanded :submit').click(function(){
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
};
the :submit selector will select all <input type="submit" />.