In my application, I have a piece of code that "catches" all the clicks on an anchor, and loads it into my page:
$("a").live("click", function () {
var src = $(this).attr("href");
if ($(this).attr("target") === "_blank")
return true;
$("#myPage").load(src + " #myPage");
return false;
});
Now this works on all anchor tags. How can I make all my POST requests (sending forms data) behave like that?
Edit: As Kevin said, I tried using .post, but it doesn't work for me, what did I do wrong? Here's the code:
$("form").post("submit", function () {
var src = $(this).attr("action");
$("#myPage").load(src + " #myPage");
return false;
});
Use the form submit event to handle form POST case
$(document).on('submit', 'form', function(){
var $this = $(this);
$.ajax({
url: $this.attr('action'),
type: 'POST',
data: $this.serialize()
}).done(function(responseText){
$("#myPage").html(responseText)
});
return false;
})
Since you are using jquery 1.9, you may have to rewrite the a handler as
$(document).on("click", 'a', function () {
var src = $(this).attr("href");
if ($(this).attr("target") === "_blank")
return true;
$("#myPage").load(src + " #myPage");
return false;
});
Related
Is it possible to debounce the click of a link? If a user clicks too many times too fast on a pjax link it'll break the load of new content.
$(document).on('click', 'a[data-pjax]', loadNewContent);
var $target = $('main.content section.context'),
$fake = $('main.fake'),
$fakeContext = $('main.fake section.context');
function loadNewContent() {
event.preventDefault();
var $this = $(this),
url = $this.attr('href');
$fake.addClass('is--loading');
$.pjax({
url: url,
fragment: 'body',
container: $fakeContext
});
$fake.one(transitionEnd, function() {
$target.html($fake.find('section.context').html());
$fake.removeClass('is--loading');
$fake.off(transitionEnd);
});
}
Any thoughts? I tried this, but it stopped the loadNewContent from firing. (https://github.com/cowboy/jquery-throttle-debounce)
$(document).on('click', 'a[data-pjax]', $.debounce(1000, true, function() {
loadNewContent();
}));
Something like this would work :
var callWaiting = false;
callAjax() {
if(!callWaiting) {
callWaiting = true;
makeHttpCall(url, data, function(response) {callWaiting = false;});
callWaiting = false;
}
}
I have a login form where we make an AJAX call to the server to perform a bit of validation before letting the login form continue submitting. The current code is outlined below:
(function ($) {
var errorMessageHtml = "";
function isUserValid(username) {
if (username.length <= 0) {
return false;
}
var userIsValid = false;
$.ajax({
async: false,
url: "/myAjaxCall?username=" + username
}).success(function (validationResult) {
userIsValid = validationResult.IsValid;
errorMessageHtml = validationResult.ErrorMessage;
}).fail(function () {
errorMessageHtml = "Error contacting server. Please try again.";
});
return userIsValid;
}
var $usernameTextbox = $("#UserName");
var $errorMessageLabel = $(".errorMessageContainer");
$(".loginButton").on("click", function (e) {
$errorMessageLabel.hide();
if (isUserValid($usernameTextbox.val())) {
return true;
} else {
$errorMessageLabel.show();
$errorMessageLabel.html(errorMessageHtml);
}
e.preventDefault();
return false;
});
})(jQuery);
I know that async: false is something that shouldn't be used since it's going out of style. My question is: What's the alternative. My click event handler needs to return true or false, meaning it has to wait for the ajax call to complete. If async: false is no longer an option, then the isUserValid method is going to return immediately without properly setting the userIsValid bool.
Now I can inline the ajax method call straight into the click event handler that's called on $(".loginButton"), but the same problem presents itself: It needs to either return true, or prevent default (i.e. prevent login) and return false depending on the result of the ajax call. Is there a way I can force the click event handler to wait for the result of the ajax call before returning, without using async: false? I understand there's a jQuery when() method, but I don't know if I can use that in this situation.
First thing, a form can be submited without clicking on respective submit button. So bind instead submit event to the form. Now depending ajax request result, you can submit the form, using e.g:
(function ($) {
var errorMessageHtml = "";
function isUserValid(username) {
$errorMessageLabel.hide();
if (username.length <= 0) {
return false;
}
var userIsValid = false;
// return the promise from ajax method
return $.ajax({
url: "/myAjaxCall?username=" + username
}).success(function (validationResult) {
userIsValid = validationResult.IsValid;
errorMessageHtml = validationResult.ErrorMessage;
}).fail(function () {
errorMessageHtml = "Error contacting server. Please try again.";
});
}
var $usernameTextbox = $("#UserName");
var $errorMessageLabel = $(".errorMessageContainer");
// "form:has(.loginButton)" or whatever more relevant selector
$("form:has(.loginButton)").on("submit", function (e) {
$errorMessageLabel.hide();
isUserValid($usernameTextbox.val())).always(function(validationResult ){
if(validationResult && validationResult.IsValid) {
this.submit();
} else {
$errorMessageLabel.html(errorMessageHtml).show();
}
}.bind(this));
e.preventDefault();
});
})(jQuery);
A. Wolff's answer is the answer I accepted, but I wanted to share my final code solution based off their input as well as the various comments made back and forth.
(function ($) {
"use strict";
var $usernameTextbox = $("#UserName");
var $passwordTextbox = $("#Password");
var $errorMessageLabel = $(".errorMessageContainer");
$("form").on("submit", function (e) {
$errorMessageLabel.hide();
var username = $usernameTextbox.val();
if (username.length <= 0 || $passwordTextbox.val().length <= 0) {
return; // Server posts back with "username/password required" so we don't handle it here.
}
$.get("/myAjaxCall?username=" + username).done(function (validationResult) {
if (validationResult.IsValid) {
this.submit();
} else {
$errorMessageLabel.html(validationResult.ErrorMessage).show();
}
}.bind(this)).fail(function() {
$errorMessageLabel.html("Error contacting server. Please try again.").show();
});
e.preventDefault();
});
})(jQuery);
I have this piece of code , that does not work , if I link JQUERY above 1.8.0
Just for curiosity, why its happening?
it takes values from select boxes, passing to pagination.php file and in the meantime showing loading image
// Pagination
$(document).ready(function () {
function loading_show() {
$('#loading').html("<img src='img/loading.gif'/>").fadeIn('fast');
}
function loading_hide() {
$('#loading').fadeOut('fast');
}
function loadData(page) {
var house_id = $("#pbthouse option:selected").val();
var sale_id = $("#pbtsale option:selected").val();
var year_id = $("#pbtsale option:selected").val();
var ipp = $("#res option:selected").val();
loading_show();
$.ajax({
type: "POST",
url: "pagination.php",
//data: "page="+page,
data: {
page: page,
house_id: house_id,
year_id: year_id,
sale_id: sale_id,
ipp: ipp
},
success: function (msg) {
$("#container1").ajaxComplete(function
(event, request,settings)
{
loading_hide();
$("#container1").html(msg);
});
}
});
}
loadData(1); // For first time page load default results
$('#container1 .pagination li.active').live('click', function () {
var page = $(this).attr('p');
loadData(page);
});
$('#go_btn').live('click', function () {
var page = parseInt($('.goto').val());
var no_of_pages = parseInt($('.total').attr('a'));
if (page != 0 && page <= no_of_pages) {
loadData(page);
} else {
alert('Enter a PAGE between 1 and ' + no_of_pages);
$('.goto').val("").focus();
return false;
}
});
$('#container1 .pagination li.active').live('click', function () {
var page = $(this).attr('p');
loadData(page);
});
$("#pbthouses").change(function () {
var page = '1';
loadData(page);
});
$("#res").change(function () {
var page = '1';
loadData(page);
});
$('#pbtsale, #pbtyear').change(function () {
var sale_id = $("#pbtsale option:selected").val();
var sale_id = $("#pbtyear option:selected").val();
var page = '1';
if (sale_id != '') {
$.ajax({
type: "POST",
url: "get_pbtsales.php",
data: {
year_id: year_id,
sale_id: sale_id
},
success: function (option) {
$("#pbhouses").html(option);
loadData(page);
}
});
} else {
$("#pbhouses").html("<option value=''
>-- No category selected --</option>");
}
return false;
});
});
Support for .live() has been deprecated since version 1.7 and removed since version 1.9. You should switch to the dynamic form of .on() which would change from this:
$('#go_btn').live('click', function () {
to this:
$(document).on('click', '#go_btn', function () {
Ideally, instead of $(document), you would pick a closer parent of #go_btn that is static (e.g. not dynamically created) as this is more efficient than using $(document), particularly if you have a number of delegated event handlers like this.
Some references for delegated event handling with .on():
jQuery .live() vs .on() method for adding a click event after loading dynamic html
Should all jquery events be bound to $(document)?
Does jQuery.on() work for elements that are added after the event handler is created?
Can someone point out what I need in my code to stop it doubling up on data when you mouseenter on the hyperlink tag. I put a flag in there isLoading but it still continues to double up. I've probably done it wrong could someone have a look through my code and see whats wrong with it - see if you can prevent it from double posting on mouseenter. Please show me you're changes - Thanks from KDM.
(function($){
$.fn.rating_display = function() {
var _this = this;
var id = $(_this).data('id');
var position = $(this).parent().position();
var left = position.left - 15;
var top = position.top + $(this).height() + 13;
var isLoading = false;
function clear_ratings() {
$('.ratings-content').html("");
}
$(document).on('click', function(e) {
var element = e.target;
/*else if($(element).closest('.rating').length){
$('.ratings-display').show();
}*/
});
// here is where I'm having trouble with double posting
$(this).on('mouseenter click', function(e) {
if(isLoading == true) return false;
$.ajax({
type:'POST',
dataType:"html",
data:{product_id:id},
url:"../../webservices/get_rating.php",
beforeSend: function() {
clear_ratings();
$('.ratings-display').show().css({'left':left + 'px', 'top':top + 'px'});
isLoading = true;
},
success: function(data) {
$('.ratings-content').append(data);
}, error:function(data, status, xhr) {
clear_ratings();
$('.ratings-content').html(data + "\r\n" + status + "\r\n" + xhr);
}
});
}).on('mouseleave', function(e) {
var target = e.relatedTarget;
if($(target).closest('.ratings-display').length) {
return false;
}else{
$('.ratings-display').hide();
clear_ratings();
isLoading = false;
}
});
$('.ratings-display').on('mouseleave',function (e) {
var target = e.relatedTarget;
if($(target).closest('.rating').length) return false;
if(!$(target).closest('.ratings-display').length) {
$('.ratings-display').hide();
clear_ratings();isLoading = false;
}
});
}
})(jQuery);
'mouseenter click' means the action is performed once at mouseenter and again if you click.
Try setting isLoading = true; before the ajax call rather than in the beforesend function. And you also want to reset isLoading = false on ajax call completion rather than on mouseleave. Depending on whether you're doing it for keyboard navigation reasons or not, you could also stop listening to the click event entirely.
I'm using this code for my main site navigation which loads each page via ajax and has fallback.
$(function() {
var newHash = '',
$contentWrap = $("#content-wrap");
$("nav").on("click", "a", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
newHash = window.location.hash.substring(1);
$contentWrap.load(newHash + " #content");
});
$(window).trigger('hashchange');
});
this works fine but when i load in the content from another page for example about.html i am also loading in some more buttons for navigation within #content-wrap.
so #content-wrap now contains a data box and some more buttons for navigation. when i click on the new navigation it needs to load new data in the data box.
first i tried just pretty much copying the script above but with new anchors however i get a conflict.
i figure i need some sort of if statement, i have looked into something like if (function !== undefined) but cannot figure out what to do.
I'm not sure how well i have explained myself, i'm confused explaining it but basically i want to combine the code above with basically the same code below without a conflict.
$(function() {
var newHash = '',
$contentWrap = $("#content-wrap"),
$aboutWrap = $("#a-wrap");
$("#content-wrap").on("click", "a", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
newHash = window.location.hash.substring(1);
$aboutWrap.load(newHash + " #a-content");
});
$(window).trigger('hashchange');
});
Update: kind of works a bit but changed my plan
$(function() {
var newHash = '',
$nav = $("nav a"),
$boxBtn = '',
$aboutWrap = '',
$contentWrap = $("#content-wrap");
$("nav").on("click", "a", function() {
$(this).addClass("nav-click");
window.location.hash = $(this).attr("href");
return false;
});
$contentWrap.on("click", "a", function() {
$(this).addClass("btn-click");
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
var $aboutWrap = $("#a-wrap"),
$boxBtn = $("div.btn a");
newHash = window.location.hash.substring(1);
if ($nav.hasClass("nav-click")){
$contentWrap.load(newHash + " #content");
$nav.removeClass("nav-click");
};
if ($boxBtn.hasClass("btn-click")){
$aboutWrap.load(newHash + " #a-content");
$boxBtn.removeClass("btn-click");
};
});
$(window).trigger('hashchange');
}); /*/end*/
I had a similar problem, basically in most cases the problem is with conflicting element ID's. In the DOM you can use an ID only once. You can workaround that by using classNames and ID's for only unique elements like wrappers.