I am developing a jQuery Mobile website and am using the jQuery validation plugin to validate my forms. On some forms I have set data-ajax="false", but still wanted to show the loading spinner when the submit button is clicked.
To display the spinner I use the following code
// Display spinner
$(document).delegate('.ajaxSpinner', 'click', function () {
if($(".ajaxValidate").length == 0 || $(".ajaxValidate").valid()) { // Show spinner if no validation or form is valid
$.mobile.showPageLoadingMsg();
}
});
The form submit button has a class of 'ajaxSpinner', and the form itself has a class of 'ajaxValidate'.
On most forms this works great, if the form is invalid when submit is clicked you don't see the spinner, whereas if the form is valid, the spinner is displayed.
I have just one single form that isn't playing nice....the spinner shows regardless of whether the form is valid or not. The form is quite long, so I'm wondering if the validation hasn't completed before my manual display spinner code fires.
I'm not very proficient with jQuery so can anyone spot the flaw in my code?
Could it be a timing issue? If it is, is there a good way to make sure the validation has completed before the click function fires?
I think you need to call the spinner inside your validation function.
So, using the validation plugin, you may normally have something like this:
$(".ajaxValidate").validate({
submitHandler : function(form) {
// START YOUR SPINNER HERE
$.mobile.showPageLoadingMsg();
$(form).ajaxSubmit({
success: function() { // YOUR FORM WAS SUBMITTED SUCCESSFULLY
// DO SOMETHING WHEN THE FORM WAS SUBMITTED SCESSFULLY ...
// ...
// STOP THE SPINNER EVENTUALLY
//$.mobile.hidePageLoadingMsg()
}
});
}
});
Hope this helps. Let me know if this works for you.
Related
I have the following:
$(document).on("pageinit", function (event) {
alert("pageinit called");
$('#logout').bind('click', function() {alert("clicked!");});
});
The first time the page runs you get a single alert 'pageinit called'. Clicking the element with id #logout fires the alert 'clicked!'. If I click any other links in this page I still get the 'pageinit called' alert (and I get it multiple times, apparently for each page I have previously navigated as well) but subsequently the handler for #logout is gone and never never re-established.
Can anyone tell me how I can get the handler for #logout to remain? I've tried:
$('#logout').die('click').live('click', function() {alert("clicked!");});
to no avail.
After looking more closely (and as commented by Omar), this problem is caused by a combination of the jquery mobile paging system AND trying to attach to a 'single' element by id.
In my case each time I clicked a link within the page it would load into the jqm paging system a separate page, each one containing its own #logout element. My solution was to query for all the buttons and attach handlers to each one:
var buttons = $("*[id='logout']");
buttons.each(function() {
// handle click or whatever here
});
Instead of:
var button = $('#logout'); // Only hooks into the first #logout element
I am loading two MVC Partial Views in jQuery UI dialog using following code for editing and adding a record:
$.get(url, function(data)
{
dialogDiv.html(data);
var $form = $(formid);
$form.unbind();
$form.data("validator", null);
$.validator.unobtrusive.parse(document);
var dat = $form.data("unobtrusiveValidation");
var opts = dat ? dat.options || '' : '';
$form.validate(opts);
//THIS FUNCTION ADDS PLUGINS ETC.
runEditCreateStartScripts();
dialogDiv.dialog('open');
});
Following is the function that wires-up chosen functionality.
function runEditCreateStartScripts(){
$("select.chzn-select").chosen(
{
no_results_text: "no match",
allow_single_deselect: true
});
}
Everything is perfect on first call. After opening one dialog say edit a few times everything is broken. There is only hyperlink available in place of chosen stuff. This also happens if I open one dialog say add and then second dialog. The bindings and other functionality from first one (add) is gone.
Any insights on why this might be happening?
The problem that caused my issue was that the modals I was loading via AJAX had inputs with the SAME ID as an input field that was already on the page (using Django that has generic ID generators for model fields). This caused collision between the two inputs when re-triggering .chosen() on the selector. When I made the ID fields unique, all worked as expected.
Hope this would have helped.
I'm using JQuery UI autocomplete feature and I'm facing a problem.
This is my code:
$("#Id").autocomplete({
source: url,
change : function (event,ui){
alert('changed');
}
});
I would like that the change event will fire any time the user type anything in the input text
It's not the case here.
when I type something it does not fire until I'm pressing with the mouse on somewhere else on the screen.
How to handle this scenario?
Try to bind a keypress event to it directly?
$("#Id").autocomplete({
source: url,
change : function (event,ui){
alert('changed');
}
});
$("#Id").bind('keypress',function(){$(this).autocomplete.change});
I solve my problem by using the keypress event separately. instead of using the change event.
The new code:
$("#Id").autocomplete({
source: url
});
$("#Id").keydown(function() {
// Logic goes here
});
This problem occurred because we got out of focus two events were fired the onBlur and the onclick event of some button I have. and this cause inconsistently behavior.
Thanks
I've been racking my head against this for 2 days now. I'm massively frustrated, and I can't seem to find any information on this with searching.
The issue. I'm using a :remote => true link to load some html from a different controller.
$('.managed_locations').bind('ajax:complete', function(evt, xhr, status){
$('#locations_modal').modal('show')
$('#locations_modal').html(xhr.responseText);
});
So it gets the html, dumps it into the bootstrap modal and displays the modal. This is working fine.
But inside of the modal I ALSO have a form which also uses :remote => true. Now to make life harder, when a button is pressed I clone the form and display it. So the user could have many forms.
Now the issue. Whenever the form is submitted it just loads it like a normal page. It's as if the :remote => true is being ignored. But this only in the modal. If I just load the modal controller by itself it works just fine. I also had this developed before using another jquery lightbox where it was working fine. I'm just switching in bootstrap for consistency.
So my initial thoughts are that the jquery_ujs.js isn't finding the new forms. So I added some code to output the form elements.
$("#log_events").click(function () {
$(document).find(".new_stored_physical_location").each(function() {
console.log( $(this).data() );
console.log( $(this).data('events') );
});
return false;
});
Which outputs in the console:
Object { type="html", remote=true}
Object { ajax:complete=[1]}
So I see that the events are being set in jQuery. Each of these forms has :remote => true and has the ajax event for when the request is complete. But it's just not doing an ajax request when I hit submit.
Is there something I'm missing that is required to make sure an ajax request will happen from the form???? The data() looks fine, the data('events') look fine. But is there some other event/binding that I need to look at?
The html that is loaded in from the modal right now is loading a layout. But i've done it both with a layout, without a layout. It's driving me nuts. Thanks for the help guys.
Edit: Some extra weirdness. The modal also loads some additional remote links, all of which are working correctly. It's only the form links which don't seem to work.
I got a solution. The big issue was within jquery_ujs.js Especially this line:
$(document).delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
FYI, rails.formSubmitSelector = 'form'. So this code found all of the forms in the document, overwrote the submit with this function. But the issue was that once you loaded in some ajax, and that ajax contained a it wouldn't add this fancy event to it. You need to re-add it.
So this is what I did.
Inside of jquery_ujs there is a bunch of functions that are accessible outside of it using $.rails. So things like: $.rails.enableElement, $.rails.nonBlankInputs. And the code for the submit event was sitting around all willy nilly. It only executes once when the page is loaded. So I put that in a function addSubmitEvent():
// Add the form submit event
addSubmitEvent: function(element) {
//$(element) was before $(document) but I changed it
$(element).delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
var form = $(this),
remote = form.data('remote') !== undefined,
blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
if (!rails.allowAction(form)) return rails.stopEverything(e);
// skip other logic when required values are missing or file upload is present
if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
return rails.stopEverything(e);
}
if (remote) {
if (nonBlankFileInputs) {
return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
}
// If browser does not support submit bubbling, then this live-binding will be called before direct
// bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
if (!$.support.submitBubbles && $().jquery < '1.7' && rails.callFormSubmitBindings(form, e) === false) return rails.stopEverything(e);
rails.handleRemote(form);
return false;
} else {
// slight timeout so that the submit button gets properly serialized
setTimeout(function(){ rails.disableFormElements(form); }, 13);
}
});
}
This is basically the exact same code. But now it's $(element) instead of $(document). This was changed because now I can sniff for when the modal has loaded in the html. Then I can call:
$.rails.addSubmitEvent('#my_modal');
I then had an issue of it adding the event too many times from when I opened/closed the modal multiple times. So I just put a simple true/false if around it to call it once only.
I'm using the remote validation in MVC 3, but it seems to fire any time that I type something, if it's the second time that field's been active. The problem is that I have an autocomplete box, so they might click on a result to populate the field, which MVC views as "leaving" it.
Even apart from the autcomplete thing, I don't want it to attempt to validate when they're halfway through writing. Is there a way that I can say "only run validation n milliseconds after they are finished typing" or "only run validation on blur?"
MVC 3 relies on the jQuery Validation plugin for client side validation. You need to configure the plugin to not validate on key up.
You can switch it globally off using
$.validator.setDefaults({
onkeyup: false
})
See http://docs.jquery.com/Plugins/Validation/Validator/setDefaults and the onkeyup option here http://docs.jquery.com/Plugins/Validation/validate.
For future reference, I found it's possible to do this in combination with the typeWatch plugin (http://archive.plugins.jquery.com/project/TypeWatch).
Basically what you want to do is (in my case for a slug):
/*Disable keyup validation on focus and restore it to onkeyup validation mode on blur*/
$("form input[data-val-remote-url]").on({
focus: function () {
$(this).closest('form').validate().settings.onkeyup = false;
},
blur: function () {
$(this).closest('form').validate().settings.onkeyup = $.validator.defaults.onkeyup;
}
});
$(function () {
/*Setup the typeWatch for the element/s that's using remote validation*/
$("#Slug").typeWatch({ wait: 300, callback: validateSlug, captureLength: 5 });
});
function validateSlug() {
/*Manually force revalidation of the element (forces the remote validation to happen) */
var slug = $("#Slug");
slug.closest('form').validate().element(slug);
}
If you're using the vanilla typeWatch plugin, you'll have to setup a typeWatch for every element because the typeWatch callback doesn't give you access to the current element via $(this), it only passes the value.
Alternatively you can modify the typeWatch plugin to pass in the element (timer.el) and then you can apply a delay to all.
For some reason (maybe because of conflicts with the unobtrusive plugin), hwiechers' answer didn't work for me. Instead, I had to get the validator of my form with .data('validator') (as mentioned in this answer) and set onkeyup to false on it.
var validator = $('#form').data('validator');
validator.settings.onkeyup = false;
We had the same problem of focusing out the autocomplete textbox "DealingWithContactName" when autocomplete suggestion list pops up. Here we select the dynamically generated autocomplete list item on which the user clicks and set focus on to it. After 50ms we take the focus out from the textbox. It solved our problem.
$('body').on('click', 'ul.ui-autocomplete li a', function () {
$('#DealingWithContactName').focus();
window.setInterval(function () {
$('#DealingWithContactName').blur();
}, 50);
});
I wanted local validation to remain during onkeyup so that the user had a tighter feedback loop. This should only affect the remote validation (that results from RemoteAttribute):
$("[data-val-remote]").keyup(function () {
// Avoid hitting server validation during onkeyup. Wait for onfocusout.
return false;
});