I have action what first need to render form by ajax and then need to update existing values. I already get rendered form with proper values, but when I click to submit form by ajax I cant prevent form submission, I have this script:
$('#edit-comment').click(function (e) {
e.preventDefault();
console.log(1);
});
But submitting with still work ! What I am doing wrong. And I dont know how I need to handle submitted form in the edit action. Here is existing part of it:
/**
* #Route("/edit/comment", name="chat_edit", options={"expose"=true})
*/
public function editAction(Request $request)
{
$comment_id = json_decode($request->getContent(), true)['commentId'];
$comment = $this->get('comment.repository')->find($comment_id);
$form = $this->createForm(new CommentType(), $comment);
return $this->render("ChatCommentBundle:Comment:form.html.twig",
array('form' => $form->createView())
);
}
Link to gist with form type
Update:
The original answer (below) still applies, but given that the form is actually loaded using AJAX, you can't bind the event listeners in the $(document).ready callback. The best option for you is to use event delegation. This is done by attaching an event listener to a DOM element that does exist from the start, but have that listener pick up on events for elements that might be added later on. For example: the body element will always exist, so you can listen for a form submission there, whether or not that form exists doesn't matter:
$('body').on('submit', '#form-id', function(e)
{
console.log('#form-id was submitted, do AJAX => submission stopped');
return false;
//or
e.preventDefault();
e.stopPropagation();
});
The why and how this works is very well explained here. It boils down to the fact that all events pass through all of the parent DOM elements of the target node, so you can attach listeners anywhere in the DOM, and handle the events before they reach their target.
I think this old answer of mine might explain a thing or 2, too. It doesn't use jQ, but it contains a simplified version of the code that jQ uses internally for delegation.
You're preventing the default effects of the click event on $('#edit-comment'), but that event still propagates through to the form. You might want to add e.stopPropagation(), too. Or simply return false; from the callback (which prevents the default and stops propagation).
However, a better way to prevent the form from being submitted is to use the submit event, and stop the submission there:
$('#form-id').on('submit', function(e)
{
console.log('Do ajax call here');
return false;
//or
e.preventDefault();
e.stopPropagation();
});
Related
I'm learning how to use jQuery and I'd like to understand what the purpose of using the off() method before submitting a form is. For example, in the following code, the form is first prevented from sending using preventDefault(), some Ajax is done and when finished, the form is finally submitted. But why do I need to use off() before submit()?
$(document).ready(function() {
$('form[name="Payment"]').on('submit', function( e ) {
e.preventDefault();
AjaxCall();
$(document).ajaxStop(function() {
$('form[name="Payment"]').off('submit').submit(); // Once Ajax request are finished, submit the form.
});
});
});
Because triggering the same event would run all that same event handler code again.
The default would always be prevented, the ajax would be called ....and then the event would be triggered again and you would have an infinite loop without changing something.
Removing the event listener would make any subsequent submit use browser default process
There are other ways around this...but this answer explains what was asked
I've got a web app which I'm trying to make run as fast as possible, one of the ways is by reducing the amount of event listeners I have attached.
I have a lot of forms (around 12). I currently check if they are submitted with:
$('#form-id').on('submit', function(){
//actions here
});
for each form. Is there a way I can do this but with only attaching one listener for a submit? and then doing a switch statement based on the forms ID to decide what actions to do?
Use delegation for submit event for all selected forms. $(this) will be the current form.
$(document).on("submit", "form", function () {
// actions here
// $(this).something...
return false;
});
return false is used to prevent the default browser behavior.
Use event delegation
$(document).on('submit', 'form', function(e) {
e.preventDefault();
// ....
});
This adds just one listener to the document which gets called anytime a form is submitted.
You can use
$('form').on('submit', function() {
//you can use $(this).attr('id') to get id of submitted form
}
to catch submit event for all form.
I'm kind of confused, I want to know binding and unbinding event on the same element is better or I should use a flag (something like 'inProgress').
I have a scenario where I have to prevent an operation or event from happening if one operation is already in process, for eg.
I have an anchor tag and I've bind an event to that anchor tag and that event handles some ajax functionality like fetching data and updating certain part of the page, what I want is to stop repeated click on the anchor tag from happening so that once the first click has happened on the anchor tag wait till the response comes from the server and the part of the page is updated, my confusion lies whether i should unbind the event once the click happens and bind the same handler again once the response is handled or should I setup a flag to check if any handler is in progress and set the flag false once the response is handled? which of the way would be efficient performance wise?
Any help/suggestion is much appreciated!
Thanks
use a flag!
it's better to use some boolean variable and check if you are allowed that action rather than calling bind and unbind (which is additional overhead).
if you use jQuery, you can use the data() to store data on that anchor.
like:
$('.testLink').on('click',function(){
//reference link
var link = $(this);
//check data
data = link.data('amIallowed');
//if no data existed yet
if(!data){
//set data and make it false to prevent further requests
link.data('amIallowed',{
allowRequest : false
});
//lets do ajax
doAjax();
}
else{ //if there was data
//and we were allowed
if(data.allowRequest){
doAjax(link);
}
}
});
//do ajax stuff here
function doAjax(link){
$.post('url',{param:val},function(){
//revert to true after request
link.data('amIallowed',{
allowRequest : true
});
});
}
if you don't use jQuery, you can still do the same feat using simple JS. jQuery uses "expando-properties" to bind data onto elements. if you can do with expando-props, use variables instead.
Jquery bind is amazing, but I don't know in what order the binding happens. My current problem is thus:
$(document.body).delegate('form', methods.checkForm);
$('form').bind('submit', methods.submitFormIfCheckedFormIsTrue);
methods.checkForm = function (e) {
if (!$(this).isVerified()) {
return false;
}
return true;
};
methods.submitFormIfCheckedFormIsTrue = function (e) {
e.preventDefault();
$.ajax("/submitForm", {
data:$(this).serialize(),
type:"post"
});
};
This is obviously not the actual code that I'm using, but it's pretty close. What happens is, the submitFormIfCheckedFormIsTrue function fires before, or during, the checkForm function, so the checking is pretty useless. My hack for it was to add the class "checked" to the form and the check if the form has that class in the other function...but then you click submit, it checks, then you have to click it again to submit it if everything went right...which is retarded.
Another thing that's important regarding this problem is that I'm they're in completely different parts of my application, for reasons that can't change. Also, they're being loaded asynchronously.
The main thing I want to know then...is how to change the order, or set the priority of the events somehow...
If you are using 'delegate' the way you have it in your example, then the ajax submission is always going to run first, so the short answer to your question is "You Can't". Your delegate is attached to the 'body' element, so events attached to elements closer to the form in the DOM tree will fire first.
Events bubble from the form -> body, so there is no ordering when you are doing that.
One option would be to have your verification trigger a second event.
methods.checkForm = function (e) {
e.preventDefault()
if ($(this).isVerified()) {
$(this).trigger('form-verified');
}
};
Then instead of binding the other handler to 'submit', you would bind it to 'form-verified'.
$('form').bind('form-verified', methods.submitFormIfCheckedFormIsTrue);
This is also another way to accomplish ordering event if they are attached to the same element instead of using delegate.
Also, if you are using jQuery >= 1.7, then you should be using on instead of bind and delegate. http://api.jquery.com/on/
Update
If both are bound to the same element, then they will be triggered in the order that they were attached to the element. Assuming checkForm is bound before the other one, then the issue is that return false; does not stop other events from firing if they are attached to the same element. For that you also need e.stopImmediatePropagation().
methods.checkForm = function (e) {
e.preventDefault()
if (!$(this).isVerified()) {
e.stopImmediatePropagation();
}
};
There is also a useful answer over here if you ever have to tweak the ordering of events. jQuery event handlers always execute in order they were bound - any way around this?
In a general sense event handlers will be called in the order that they were bound, but only if they're bound at the same level. In your case you're binding one directly to the form while the other is a delegated handler bound at the document.body level. The directly bound one will happen first and then the event bubbles up to be handled by the other.
If you bind both handlers at the same level with .delegate() then they should be called in order:
$(document.body).delegate('form', 'submit', methods.checkForm);
$(document.body).delegate('form', 'submit',
methods.submitFormIfCheckedFormIsTrue);
Then in the first (generic) handler you should call the event.stopImmediatePropagation() method to prevent other handlers being called (noting that simply returning false prevents the default and stops the event bubbling up further, but it doesn't stop other handlers at that level from running):
methods.checkForm = function (e) {
if (!$(this).isVerified()) {
e.stopImmediatePropagation();
return false;
}
return true;
};
(By the way, the code shown in the question left out the event (second param) from the .delegate() call - I've put it in in my code.)
Or bind both handlers directly rather than using .delegate(). And speaking of using .delegate(), if you're using the latest version of jQuery you may like to switch over to using .on(), the new do-everything event binding method.
"What happens is, the submitFormIfCheckedFormIsTrue function fires before, or during, the checkForm function"
Definitely before, not during. (In pretty much all browsers) JavaScript runs on a single thread, so you will not ever have two functions running simultaneously.
I've got an onsubmit handler added to a form like so:
$('#content_form').bind('submit',function(e) {
source = $(e.target).attr('name');
alert(source);
return false;
});
so e.target = the form element. I'm using several submit buttons, and need to determine which one was actually clicked (in modern browsers, that clicked button is the only one that submits, I'm doing this for IE6 compat - it submits the values of all the buttons).
My only thought it to kill any onsubmit events, and then tie click events to the buttons themselves. This would kill the form functionality entirely if javascript wasn't enabled, so I'd like to avoid this.
An easy (but possibly naive) implementation would be to have the onclick handler for each button set a field indicating which one was the last one clicked. In your submit handler, you could then check the value of this field.
$('#content_form input:submit').bind('click', function(e) {
$('#content_form').submit();
// you can now reference this or $(this),
// which should contain a reference to your button
});
Have you checked out the jQuery Form Plugin? It handles submitting forms via ajax very nicely and will handle this problem (along with many others) for you.
Something else you could do is use preventDefault(); instead of return false