jQuery: having trouble with code to disable link after ajax event - javascript

Goal:
Disable links before ajax:success is received. (then i'll tell my app server thing to enable the links. I'm writing a simple board game, and don't want to be recieving multiple ajax requests before the first one is responded to, because it messes with the game logic.
<script type="text/javascript">
var disableLinks = false;
$("a").click(function(e){
if (disableLinks){
e.preventDefault();
}
});
$("a").ajaxStart(function(){
disableLinks = true;
});
$("a").ajaxStop(function(){
disableLinks = false;
});
</script>
And here are what the links look like:
<a href="/board/take_turn?id=313&x=1&y=2" data-remote="true">
<div class="ttt_square">
</div>
</a>

This is because your AJAX start and finish events never fire. Why? Because simply clicking a link isn't an AJAX request, and doesn't trigger the global AJAX events. To use the global AJAX events, you need to use an AJAX function such as .get( ), .load( ), or $.ajax( )
The code below, is mostly yours... I've just added 2 lines (which could even be reduced to 1, but I think it looks better this way)
var disableLinks = true;
$('a').click( function( e )
{
if( disableLinks )
{
e.preventDefault( );
}
var self = $(this);
$.ajax( { "url": self.attr( 'href' ) } );
} );
$('a').ajaxStart( function( )
{
disableLinks = true;
} );
$('a').ajaxStop( function( )
{
disableLinks = false;
} );

You've got a typo. e.prevenDefault(); should be e.preventDefault();
And this should be enough for disabling the default action. So you can rid of your onclick.
$("a").click(function(e){
e.preventDefault();
});
Edit:
Maybe this: jQuery - How can I temporarily disable the onclick event listener after the event has been fired?
or this: jQuery - How can I temporarily disable the onclick event listener after the event has been fired?
should solve your problem (if understand you correctly)

try this:
$('a').click(function(){
if (!this.hasClass('disabled')) {
this.addClass('disabled');
var self = this;
$.ajax({url: this.attr('href'),
complete: function(jqXHR, textStatus)
self.removeClass('disabled');
}
});
}
return false;
});

Related

Handling multithreadiing issue in javascript/jquery?

$(".getDetails").click(function() {
// some stuff like fetching response from server
})
when user clicks getDetails button on UI multiple times within fraction of second , jquery generates two calls for click function and my logic fails.
I think solution to this will be to disable the button on first click itself(so that use can't click multiple times). Once i get the response or just before returning
from click method i make it enable. Is there any better solution ?
If no, how can i make button disable as soon as user click button first time. I think it needs to be done before calling click method or some where in html element ?
Java provides synchronized keyword so that only one thread enters at time inside method , i am not sure is similar thing exist in javascript or not ?
Assuming the click handler executes an AJAX request you can set the button as disabled before making the request, then enable it again once the request completes. Try this:
$(".getDetails").click(function(){}
var $btn = $(this).prop('disabled', true);
$.ajax({
url: '/foo'
success: function() {
console.log('It worked!');
},
error: function() {
console.log('It failed!');
},
complete: function() {
$btn.prop('disabled', false);
}
});
});
you can try unbinding click event and after ajax call again bind click to that class
$(".getDetails").click(function(){}
$(".getDetails").unbind('click');
// some stuff like fetching response from server
)
You can use simple flag to prevent firing your logic multiple times:
var flag = true
$(".getDetails").click(function() {
if (flag) {
flag = false;
//your logic...
//when your code ends (in after-AJAX callback for example)
flag = true;
}
});
$(".getDetails").click(function(e){
var $target = $(e.currentTarget);
// assuming the click listener is on the button
$target.prop('disabled',true);
// request, stuff...and when done:
$target.prop('disabled',false);
})
try Prevent Default and return false to avoid any other event propagation
This is solution is like semaphore or monitor
var progress = false;
$(".getDetails").on('click', function(e) {
if(!progress){
progress = true;
// some stuff like fetching response from server
//also after sucessfull fetch make true to false again
}else{
console.log('something in progress');
}
e.preventDefault();
return false;
})
This should make sure that your button will not fire the async request twice, until you have a response.
function doAjaxReq() {
/*
Add your ajax operation here
as a return value of doAjaxReq
like so:
return $.ajax({
url: '/foo',
type: 'POST',
data: data
})
Since i can't use ajax here let's smilulate
it useing a promise.
*/
promise = new Promise(function(res, rej) {
setTimeout(function(){
res({foo: "bar"});
}, 1000)
})
return promise;
}
/*
Inside here you add the click handlder
only once use `elem.one('click'...`
*/
function addClickHandler(elem) {
elem.one('click', function() {
// do your ajax request and when its
// done run `addClickHanlder` again
// i'm using `.then` because of the promise,
// you should be using `.done`.
doAjaxReq().then(function(data) {
console.log(data);
addClickHandler(elem);
});
})
}
addClickHandler($(".getDetails"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="getDetails">Get Details</button>

JQuery conditional preventDefault() firing when not called

I have the following script I've written.
<script>
$(document).ready(function(){
$('a').data('loop',true);
$('body').on('click', 'a', function(event){
console.log($(this).data('loop'));
if ($(this).data('loop') == 'true') {
console.log('hit');
event.preventDefault();
caller = $(this);
$(this).data('loop',false);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({linkref: linkref, linkpos: linkpos, screenwidth: screenwidth});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
data: "json=" + json_data,
complete: function (jqXHR, status) {
console.log(status);
console.log(caller);
$(caller).click();
}
});
} else {
console.log(event.isDefaultPrevented());
console.log('miss');
$(this).data('loop',true);
}
});
});
</script>
It works, sends me the details I want etc etc. BUT!!!
When I click a link, It fires off the details to me via Ajax, then it's meant to "click" the event again, which it does! but the event does not fire it's normal action. So When clicking a link to another page, I would go to that other page... that's not happening.
If I comment out the line event.preventDefault(); Then the event fires as I would expect...
So to me it looks like the event.preventDefault is executing even though it's not meant to be during the second call...
Sorry if this is a bit complicated to understand. I don't quite understand what's happening myself.
Is it possibly a bug, or is there something that I've done that has caused this?
I didn't think I could, but I have successfully made a jsfiddle for this.
https://jsfiddle.net/atg5m6ym/2001/
You can try this and not worry about the "loop" anymore:
$(document).ready(function () {
$('body').on('click', 'a', function (event) {
event.preventDefault();
var caller = $(this);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({linkref: linkref, linkpos: linkpos, screenwidth: screenwidth});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
data: "json=" + json_data,
complete: function (jqXHR, status) {
console.log(status);
console.log(caller);
window.location.href = linkref; // Redirect happens here
}
});
});
});
UPDATE
There's a few issues to note here:
1) Some links don't require a redirect (as noted, bootstrap model links that control showing/hiding or within document anchors
To correct this it really depends on the case. Usually bootstrap adds specific classes or data attributes to the links so you can do something like.
$('body').on('click', 'a:not(list of things to exclude)'..
Personally I'd instead define the links I wanted to track as :
<a href=<link> data-tracked='true'...
<script>
$('body').on("click","a[data-tracked='true']"...
Or if you want to track most links with a few exceptions you can:
<a href=<link> data-tracked='false'...
<script>
$('body').on("click","a:not([data-tracked='false'])"...
Or more generally:
<script>
$('body').on("click","a", function () {
if ($(this).attr("data-tracked") == "false" || <you can check more things here>){
return true; //Click passes through
}
//Rest of the tracking code here
});
The following if statement will return true whenever the data-loop attribute exists against an element, regardless of it's value:
if ($(this).data('loop')) {
It needs to be changed to check for the value:
if ($(this).data('loop') == 'true') {
When you assign anything to be the value of an element attribute it becomes a string and, as such, requires a string comparison.
Event.preventDefault() is not being executed second time.
Link redirection happens when the method is completed.
So in your case redirection will happen when complete method of ajax call is completed.
lets say, we have event1 and event2 object in the code. event1 is the object in the ajax call method and event2 is the event object in recursive call (second call) method.
so when link is clicked second time , we still have complete method to be executed. as soon as it returns to the complete method of ajax call, it finds the event1 is having preventDefault property true and it does not redirect.
Try this ;)
$(document).ready(function(){
$('body').on('click', 'a', function(event){
event.preventDefault();
var caller = $(this);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({
linkref: linkref,
linkpos: linkpos,
screenwidth: screenwidth
});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
/* To temprary block browser; */
async: false,
data: "json=" + json_data,
complete: function(jqXHR, status){
/* add class **ignore** to a element you don't want to redirect anywhere(tabs, modals, dropdowns, etc); */
if(!caller.hasClass('ignore')){
/* Redirect happens here */
window.location.href = linkref;
}
}
});
});
});

AJAX returns data only after first click

I have this ajax request script:
function SendData(){
$( "#Submit" ).click(function() {
$('#Submit').attr("disabled", true);
$.ajax({
type:"POST",
url:"assets/process.php",
data: {
Years : $('#Years').val()
},
success: function(Response){
if (Response.Status == 'Error') {
swal("Ups!", "Nemo' zebavaš", "error");
} else if (Response.Status == 'Error0') {
swal("Ups!", "Servis 'Misterije' mogu koristiti samo rođene osobe!", "error");
}
else if (Response.Status == 'Error120') {
swal("Ups!", "Žao nam je! Niste podobni za korišćenje WEB Servisa 'Misterije'!", "error");
}
else if (Response.Status == 'Success') {
swal("USPEŠNO!", 'Rođeni ste: '+Response.Calculated+' godine!', "success");
}
$('#Submit').attr("disabled", false);
}
});
});
}
When I load page in browser, add data to input and click on button nothing happens, but on second and all clicks after until I refresh page all working OK.
How I can slove this problem?
Don't call the function
Put your code in $(document).ready function
Presumably you're calling this SendData() function when you click the button?
This function isn't doing what you think it's doing. It's not invoking the AJAX request. All this function does is attach the click handler to the button. Nothing more. Then the next time you click the button, that handler will execute.
(Not to mention that it would also again attach another click handler. So the third click would invoke the handler twice. And so on...)
There's no need to wrap all of this in a function. Instead of this:
function SendData(){
$( "#Submit" ).click(function() {
// your code
});
}
just do this:
$( "#Submit" ).click(function() {
// your code
});
This will attach the click handler, not invoke it. Any time afterward when you click the button the handler will be invoked.
At worst, you'd have to do this if the button doesn't exist yet when this code executes:
$(function () {
$( "#Submit" ).click(function() {
// your code
});
});
This would wait until the document.ready event and then attach the handler.
(Note: You'll also want to remove any reference to SendData() once you've removed that function. I'm assuming you're calling it in-line from the button. But you don't need to do that when you're attaching a click handler with jQuery.)

Jquery function doesn't work after Ajax call

I've got this function:
$(document).ready(function() {
$('.post_button, .btn_favorite').click(function() {
//Fade in the Popup
$('.login_modal_message').fadeIn(500);
// Add the mask to body
$('body').append('<div class="overlay"></div>');
$('.overlay').fadeIn(300);
return false;
});
My page loads content with favourite buttons, but after Ajax call and generated additional new content the function doesn't work when you click new content's buttons. What could be not right?
That is because you are using dynamic content.
You need to change your click call to a delegated method like on
$('.post_button, .btn_favorite').on('click', function() {
or
$("body").on( "click", ".post_button, .btn_favorite", function( event ) {
Instead of this:
$('.post_button, .btn_favorite').click(function() {
do this:
$(document).on('click','.post_button, .btn_favorite', function() {
on will work with present elements and future ones that match the selector.
Cheers
class-of-element is the applied class of element. which is selector here.
$(document).on("click", ".class-of-element", function (){
alert("Success");
});
If you know the container for .post_button, .btn_favorite then use
$('#container_id').on('click', '.post_button, .btn_favorite', function () { });
so if '.post_button, .btn_favorite' are not found then it will bubble up to container_id
else if you don't know the container then delegate it to document
$(document).on('click', '.post_button, .btn_favorite', function () { });
Reference
I am not sure if I am getting your question right but you may want to try..
$.ajax({
url: "test.html"
}).done(function() {
$('.post_button, .btn_favorite').click(function() {
//Fade in the Popup
$('.login_modal_message').fadeIn(500);
// Add the mask to body
$('body').append('<div class="overlay"></div>');
$('.overlay').fadeIn(300);
return false;
});
Just try to paste your code inside done function.
Hope it helps :)
EDIT:
I also notice you are missing }); on your question.
The following worked for me
$(document).ready(function(){
$(document).bind('contextmenu', function(e) {
if( e.button == 2 && jQuery(e.target).is('img')) {
alert('These photos are copyrighted by the owner. \nAll rights reserved. \nUnauthorized use prohibited.');
return false;
}
});
});
You need to bind the jQuery click event once your ajax content is replaced old content
in AJAX success block you need to add code like here new response html content one a tag like
Click Me
So you can bind the new click event after change the content with following code
$("#new-tag").click(function(){
alert("hi");
return false;
});

Capture a response from jquery submitForm

I have the following code that I use with Yii framework to delete one register.
This code is automatic generated and I'd like to capture if it was submited when the dialog open. If the ajax is complete I'll save in my user log.
jQuery(function($) {
jQuery('body').on('click','#yt0', function(){
if (confirm('Want to delete it?')) {
jQuery.yii.submitForm(this,'/yiiProject/index.php?r=project/delete&id=168',{});
return false;
}
else
return false;
});
jQuery('body').tooltip({'selector':'a[rel=tooltip]'});
jQuery('body').popover({'selector':'a[rel=popover]'});
});
Most you can do as far as I can see is override the confirm method and handle the case when user click OK:
var originalConfirm = window.confirm;
window.confirm = function(msg) {
if (originalConfirm(msg)) {
//log...
return true;
}
return false;
};
You can also override Yii auto generated code completely by sumbitting the AJAX yourself then always returning false:
if (originalConfirm(msg)) {
$.post("/yiiProject/index.php?r=project/delete&id=168", function() {
//success, write to log...
});
return false;
}
Try to use the global ajax events:
http://api.jquery.com/ajaxSuccess/
$( document ).ajaxSuccess(function( event, xhr, settings ) {
if ( settings.url == "ajax/test.html" ) {
$( ".log" ).text( "Triggered ajaxSuccess handler. The ajax response was: " +
xhr.responseText );
}
});

Categories

Resources