jQuery .delegate Not Working on Form Load via AJAX - ajax

I am submitting and loading a new form via AJAX and want to use the same script that the first form uses to submit and load the new form to submit a comment. I have this script commented out so you cannot see it but when I use it, the commentForm.php loads and does not use the jQuery submission. I have tried it many ways with no luck.
$('#quoteForm').delegate('input:submit', 'submit',function(e) {
Any help would be appreciated.

If your form is getting replaced then you'll need to delegate the event handler to a parent element. And you'll need to bind to the form and not the submit button:
$('body').delegate('form', 'submit', function(e) {
// and you'll need this to prevent
// the form's 'default' action
e.preventDefault();

Related

RAILS 6 Ajax events and Ajax Spinner

I am trying to show a loading animation / spinner on every Ajax request
my application.js
$(document).on("turbolinks:load", function() {
window.addAjaxLoaderHandler();
});
window.addAjaxLoaderHandler = function() {
$(document).on('ajax:send', function() {
$('#ajax-loader').show();
});
$(document).on('ajax:complete', function(){
setTimeout(() => {$('#ajax-loader').hide();}, 100);
});
}
This works perfectly, UNTIL I load a remote form by AJAX. If I submit that newly loaded form the ajax:send fires, but after completion (without any errors) the ajax:complete does not (the spinner will not be hidden).
The problem seems to be that I remove the loaded form with the ajax call.
What can I do to make this work?
I am just trying to click a link, load a form and remove the form after sending its information.
UPDATE
My application.html.haml (I use HAML so syntax is accordingly, so #... means <div id="...">#all indented code lines#</div>)
#main
= yield
#ajax-loader
The form will be loaded like:
$('#main').append('<%= j(render(:partial => 'new', :locals => {:model => #model})) %>');
The problem is that #ajax-loader is not hidden and still shows after form is submitted.
I think the problem is, that I remove the AJAX-call triggering element. But I was hoping, that since I bound the listener to document, that it still triggers.
Of course in this case I just can do $('#ajax-loader').hide();, but I am trying to understand why ajax:complete is not fired.
I guess you answered your own question: the problem is that when you remove the form, so does the event listener.
You can check what event listeners still apply to your document object using
getEventListeners(document). Try this on your console* after the spinner is fired and refuses to hide.
*edit: this is a Google Chrome function, might not work in other browsers, though most of them have ways to inspect the listeners on a node
I think of these workarounds:
a) Rebinding the listeners everytime you remove a form;
b) Attaching the listener to the window object instead of document
c) If you are using jQuery Ajax you could use the beforeSend and complete properties to show and hide the spinner instead of events. If it's not jQuery Ajax there's probably a similar way to achieve the same behavior.

Wiring up Ajax.BeginForm that didn't exist during doc.ready?

I have a MVC page that loads a Partial via a Ajax.ActionLink, which works, and then the loaded Partial contains a form that has Ajax.BeginForm. This form is not getting wired up to unobtrusive ajax, and instead is performing a page refresh(I verified this in the Network log of the browser that shows the initiator when I click submit is the browser instead of jquery).
What I believe is the issue is that since the form didn't exist when the page is loaded(but later is added via the Ajax.ActionLink), then unobtrusive ajax didn't see the data-ajax attributes on the newly added form and wire up the necessary events. I'm assuming that only happens at document.ready, and the ajax form didn't exist then.
Is there something I can do to say "hey Unobstrusive Ajax, please look at my page again now that I have some new elements that are marked with data-ajax and wire them up"?
Thanks.
Looking at the unobtrusive ajax source, it has this:
$("form[data-ajax=true]").live("submit", function (evt) {
var clickInfo = $(this).data(data_click) || [];
evt.preventDefault();
...
The form tag generated looks like this:
<form action="/Path/Create" class="form-horizontal" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#ParentContainer" id="PathForm" method="post" novalidate="novalidate">
As far as I can tell the selector on the .live event should be picking up on the new form when it's loaded onto the page. The form is inside a bootstrap modal however, so I don't know if that would be preventing the event from bubbling up somehow.
I can even run this in Chrome console:
$("form[data-ajax=true]").live("submit", function (evt) {
var clickInfo = $(this).data(data_click) || [];
evt.preventDefault(); });
And it returns the form element successfully, but when I click submit it still does a full page refresh. I would expect it to at least do nothign since I wired it up to preventDefault.
To answer my own question regarding unobtrusive ajax and dynamically loaded content, it should work fine out of the box. The way it wires up to events with .live(deprecated, still works currently) should detect forms that are loaded dynamically onto the page. So apparently it doesn't suffer the same problem that unobtrusive validation does.
Our problem was unrelated to that. We were using bootstrap modal which spawned a modal div from inside a form. Since the modal then loaded another page containing a form, we realized we had a form within a form (even though it didn't really look that way since the other form was in a modal).
To solve this we moved the declaration of the modal div in the first form outside of the form. We could still have a link that referenced the modal to show it, but not the modal's inner form wouldn't be nested in the first form.
I believe the reason this caused both the .live and .on methods to not catch the event was because they depend on the event to bubble up to the document, and it bubbled up only as far as the outer form which was not an ajax form, thus did not match the selector.
Another solution would have been to write .on more like this so that the event would be caught when it bubbled up to the container of the inner form, instead of scoping it to the document where the event would reach the outer form first.
$('#innerModalId').on("submit", "form[data-ajax=true]", function (evt) {
evt.preventDefault();
...
return false
});
However since this was part of a library, that's not an ideal solution as I would have needed to repeat their code. We didn't get as far as updating unobtrusive ajax:
http://nuget.org/packages/jQuery.Ajax.Unobtrusive
But I think we would have still had the problem since even with .on it still didn't work due to our page structure problem.

Ajax Contact Us Form Validation - Cakephp 2.0

I'm having a website http://1008designs.in/ There in the home page I have built a Enquiry Form, The form usual validation works fine, but I need Jquery & Ajax validation, the form submits to 'enquiry/add', Pls help me on how to use Jquery Ajax in cakephp 2.0, I gone through a video of Andrew Perkins, but It didn't work for me. If I submit the form, then the whole home page is displayed on that Enquiry Div. I'm trying it from a week, but not working, pls help me as soon as possible.
When you submit form with ajax to controller enquiry/add the html returend by ajax request is a view associated with this enquiry/add. If you want to customize this html you have to modify add action in controller:
At the end of the action try this:
if($this->request->is('ajax'))
{
$this->autoRender = false;
$this->render('/elements/enquiry_success');
}
And in app/view/elements/ add enquiry_success.ctp containing some html/php code which will be returned to #succces div (for example <p>Enquiry added!!!</p>).
This code detects if request is ajax and id it is it doesnt render default view for action but some element.

How to force form client-side validation in or before $.ajax()

I have a form and unobtrusive validations are enabled. By default in submit method client side validation gets triggered and (if you have any errors) the form looks like this:
The validation happens even before any data gets sent to the server.
Now this behavior doesn't work if you want to use $.ajax method. Client side validation doesn't work. You have to manually check all the fields in your javascript, losing all the beauty of DataAnnotations.
Is there any better solution? I could've use jquery's submit() but I guess it doesn't have callback like $.ajax.
Oh...
if (form.valid()) // do submit
You must force the form to validate before checking if it is valid. Something like this:
var form = $( "#myform" );
form.validate();
if (form.valid()) {
// ...
}
I did...
$("#form-submit-button").click(function (e) {
e.preventDefault(); // Stops the form automatically submitting
if ($("#my-form").valid()) {
$("#my-form").submit();
}
});
This also seems to be a good solution if you have say textboxes with a plugin to make those textboxes into a calendar control. Only reason I say this is because I used Zebra Datepicker with an MVC form and it would submit an invalid form if focus was on the calendar date picker. Using the below code stops this.
I was having the same issue Yablargo was having in that it was saying that valid is not a function, so I came up with this:
For the onclick handler of the submit button, I put this:
onclick="return $(this).closest('form').checkValidity();"

jQuery Showing an Ajax loader during transmission & Prevent Multiple Submits

I have an app that has several different types of form elements which all post data to the server with jQuery AJAX.
What I want to do is:
Show a loader during AJAX transmission
Prevent the user from submitting twice+ (clicking a lot)
This is easy to do on a one off basis for every type of form on the site (comments, file upload, etc). But I'm curious to learn if that is a more global way to handle this?
Something that's smart enough to say:
If a form is submitting to the server and waiting for a response, ignore all submits
Show a DISABLED class on the submitted / clicked item
Show a loading class on the class="spinner" which is closest to the submit item clicked
What do you think? Good idea? Done before?
Take a look at the jQuery Global Ajax Event Handlers.
In a nutshell, you can set events which occur on each and every AJAX request, hence the name Global Event Handlers. There are a few different events, I'll use ajaxStart() and ajaxComplete() in my code sample below.
The idea is that we show the loading, disable the form & button on the ajaxStart() event, then reenable the form and hide the loading element inside the ajaxComplete() event.
var $form = $("form");
$form.ajaxStart(function() {
// show loading
$("#loading", this).show();
// Add class of disabled to form element
$(this).addClass("disabled");
// Disable button
$("input[type=submit]", this).attr("disabled", true);
});
And the AJAX complete event
$form.ajaxComplete(function() {
// hide loading
$("#loading", this).hide();
// Remove disabled class
$(this).removeClass("disabled");
// Re-enable button
$("input[type=submit]", this).removeAttr("disabled");
});
You might need to attach to the ajaxError event as well in case an AJAX call fails since you might need to clean up some of the elements. Test it out and see what happens on a failed AJAX request.
P.S. If you're calling $.ajax or similar ($.getJSON), you can still set these events via $.ajaxStart and $.ajaxComplete since the AJAX isn't attached to any element. You'll need to rearrange the code a little though since you won't have access to $(this).
I believe you have to do 2 for sure and 3 to improve usability of your app. It is better to keep backend dumb but if you have a security issue you should handle that too.

Resources