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

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.

Related

Reload javascript after thymeleaf fragment render

I have javascript files defined in the <head> of both my layout decorator template and my individual pages which are decorated. When I update a thymeleaf fragment in one of my pages the javascript defined in the head of the parent page no longer works. Is there a standard way to 'refresh' these js files?
Thanks.
Additional clarification :
I have a form submitted by an ajax call which updates a table in the page. I have a Jquery onClick function targeting a button in the updated table. The javascript doesn't seem able to bind to the returned elements in the updated part of the page. I select by element class and can see that the selection works prior to the partial fragment render.
For me it is unclear what you mean by
javascript defined in the head of the parent page no longer works.
The page is created on the server. Normally it contains urls of the javascript files
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
In this case 'refreshing' the javascript files can happen only in the client.
Check the html of the page in the client.
Are the tags as expected ?
Are there tags for all expected javascript files ?
With the browser tools (for example Google Chrom developer tools ) check that all script files are actually loaded.
If this doesnt help, it could be that the order of the script tags has changed between the first and second load. This could cause a different behaviour of the javascript executed in the browser.
EDIT :
With the initial load you bind javascript callbacks to dom elements.
You do this directly or through Jquery or other libraries.
When a new dom element is loaded, it has no callbacks bound to it, even if it has the same id as a replaced dom element.
So after the load you have to bind your callbacks again.
If you bound them 'by hand', just bind it again.
If you are using a JQuery plugin, that made the bindings, look into the code or documentation, many of them have a function for that or you can call initialization again.
Once you added new content to the DOM you need to bind again the new content.
Let's say I have a button with some class, the event in binded to the class:
<button class="someclass">Button 1</button>
<script>
var something = function() {
// do something
};
$(".someclass").on("click", something);
</script>
If I add more buttons from the same class to the DOM, they will have not have the click event binded. So once you load the new content via ajax, also remove all binding and add again (you need to remove or you will have buttons with 2 events).
$(".someclass").off("click");
$(".someclass").on("click" , something);

wicket: how to update a form component with ajax, not the whole form

I've got a wicket dropdown choice, and when I select something, I want to update some components within the form. This is working fine using wicket (1.4) ajax. However, it's updating the whole form including the dropdownchoice itself. There are quite a lot of items in the dropdown list (maybe 2000) so it's not great from a performance point of view.
Here's the page hierarchy:
form (Form)
|----packageDDC (DropDownChoice)
|----pptview (RefreshingView)
|----buy (Button)
packageDDC.add(new AjaxFormComponentUpdatingBehavior("onchange") {
protected void onUpdate(AjaxRequestTarget target) {
//--snip-- update pricepoints which back up the pptview
target.addComponent(form); //ie the form
}
}
In the ajax debug window I can see all the dropdown choice options being re-sent every time
What I want to do is only update the pptview and the Button via ajax, not the contents of the dropdownchoice.
I tried adding pptview to the target, but it complains that RefreshgViews can't be updated via ajax.
I tried wrapping the pptview with an EnclosureContainer, but wicket didn't like that either (something about setRenderBodyOnly)
So I tried using an WebMarkupContainer (called 'pptcontainer') and setting pptview to be a child of that - but now the pptview is not updated. Instead it says (in Ajax debug):
"ERROR: Wicket.Ajax.Call.processComponent: Component with id [[purchaseButton2f]] was not found while trying to perform markup update. Make sure you called component.setOutputMarkupId(true) on the component whose markup you are trying to update."
"ERROR: Wicket.Ajax.Call.processComponent: Component with id [[pptcontainer2e]] was not found while trying to perform markup update. Make sure you called component.setOutputMarkupId(true) on the component whose markup you are trying to update."
well these objects definitely do have this set to true:
buy.setOutputMarkupId(true);
pptcontainer.setOutputMarkupId(true);
pptcontainer.setOutputMarkupPlaceholderTag(true);
So the page is not updated correctly.
What am I doing wrong?
The new hierarchy is:
form (Form)
|----packageDDC (DropDownChoice)
|----pptcontainer (WebMarkupContainer)
| |----pptview (RefreshingView)
|----buy (Button)
I faced same problem with popup window which content is provided by ajax call. In my case the problem was solved by changing html placeholder "wicket:container" to "div" element as proposed in this article: http://sha.nnoncarey.com/blog/archives/36
After this change generated html has correct id and wicket do not have problem to find it and replace content with AJAX response.

Loading forms with .load kills the submit button in Firefox

I am currently loading several forms into a webpage with:
$(document).ready(function () {
$('#content').load('php_script.php', function() {
$(this).find('#someForm').ajaxForm(function() {
alert('Success!');
});
$(this).find('.someOtherForm').ajaxForm(function() {
alert('Success!');
});
});
});
This works in Chrome, Chromium and IE who loads the forms and everything works as it should (Clicking submit sends a request to the php-script defined in the form's action, which adds stuff to a db, and shows the alert dialog). In Firefox (v10.0.2) this code loads the forms into the DOM and displays them, but when clicking submit on any of the forms nothing happens.
At first I suspected ajaxForm, but changing the above code to:
$(document).ready(function () {
$('#content').load('php_script.php');
});
yields almost the same result, the difference being that the user is sent to the script defined as the action (Except for Firefox, where nothing happens).
How do I make Firefox not kill the submit button?
I solved it, bad HTML from my side:
<table><form ...>
<tr>...</tr>
</form></table>
Instead it should look like:
<form ...><table>
<tr>...</tr>
</table></form>
The validator did not catch this since it was loaded via jQuery (and I forgot to validate the page serving the forms), and Firefox buggered out.
The code above looks ok to me...
Have you had a look in firebug if there are any errors? Maybe there is a conflicting Id or something.
Maybe the form isnt completely loaded into the dom yet, might be worth giving live binding a try
Found this in the docs:
...jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as , , or elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser...
If you inspect the form is it the same as in other browsers?

Ajax content getting loaded multiple times with JQuery UI Tabs

Hi
I am basically calling individual php pages (and their forms) via AJAX in separate JQueryUI tabs. The code is something like:
<div id="dock">
<ul>
<li>Home</li>
<li>Profile</li>
<li>Statistics</li>
<li>Pings</li>
</ul>
</div>
...
jQuery(function($) {
jQuery('#dock').tabs({'collapsible':false});
});
1) Now every time I click on the tabs, their content gets loaded fine but the previous content does not get destroyed. As a result, imagine if a tab was clicked (loaded) N times - a form is also submitted N times. As far as I have understood, multiple bindings occurs here and hence the multiple form submits. How can I prevent this?
2) I have separate forms in each tab. When multiple tabs are selected, multiple forms get loaded. Now if I submit a value (via AJAX) in any one of the form, the data is submitted across all the forms which were previously loaded (Checked with Firebug). How can I prevent this again ?
PS: Enabling caching in tabs partially solved problem #1, but does not help with problem #2.
PPS: I went through quite a few similar posts but I am still stuck :(
Thanks !
From the little bit of code there, it looks like your problems may arise from using the same page (index.php) for each of the tabs. Check these:
Does each form have a separate ID? They should.
Disable caching in both 'cache' and 'ajaxOptions'. This will make sure content is refreshed (and removed) with each click.
How are your forms submitting via AJAX? Regardless of the method, you should handle your form bindings for each tab select through the "load" option.
Try this...
$("#dock").tabs({
load: function (event, ui) {
//setup new content bindings here
},
cache: false,
ajaxOptions: {
cache: false
}
});

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