Given my below code Is there a way i can get alert when my ajax process is still in progress?
as you have already noticed code for alert will never get executed because of obvious reason that async ajax will keep happening but the value of click false will come before that and i will never be able to get alert during ajax call. Is there any way i can get alert when ajax request still in process?
<html>
<body>
<button type="button" id="submit-catalog" class="btn btn-primary">Activate</button>
</body>
</html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
var clicked = false;
$(document).on('click', '#submit-catalog', function() {
clicked = true;
//doing some ajax call which is taking time
});
if(clicked){ // never get executed
alert("button clicked")
//i am executing some function only if that button clicked
}
});
</script>
Your logic is off; here's how to do this:
var clicked;
$(document).ready(function() {
$(document).on('click', '#submit-catalog', function() {
if (clicked) {
console.log("ajax still in progress");
return false;
}
clicked = true;
console.log("starting ajax");
setTimeout(function () {
clicked = false;
console.log("ajax done");
}, 3000);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button" id="submit-catalog" class="btn btn-primary">Activate</button>
I'm not sure if this is what you're looking for, but this will prevent the ajax from firing again and again based on the variable which keeps track of the ajax progress.
It's not about Ajax. Code is getting executed top to bottom, you declared event listener on the document and it waits for action, while your 'if' statement was already processed.
This 'Alert' or any other action should be done within event listener
Also, if you want to do any action before executing ajax request you simply use beforeSend: ()=>{/*your actions*/}, and then after ajax request is done success: callback=>{/*do when done*/}
which may look like that:
$.ajax({
url: url,
method: 'POST',
beforeSend: ()=> { alert('clicked') },
success: callback=> { console.log(callback) }
})
You can also use : one() instead of on() only if you don't use the clicked variable somewhere else. You attach the event for only one trigger. At the end of the callback you reattach it.
$(document).ready(function() {
function foo(e){
setTimeout(function () {
console.log("ajax done");
$(e.delegateTarget).one('click', '#submit-catalog', foo)
},1000)
}
$(document).one('click', '#submit-catalog', foo);
});
Other solution : add class to stop the propagation thanks to delegate event
$(document).ready(function() {
$(document)
.on('click', '#submit-catalog.prevent', function(e){
e.stopImmediatePropagation();
}
.on('click', '#submit-catalog', function(){
$(e.currentTarget).addClass('prevent');
setTimeout(function () {
console.log("ajax done");
$(e.currentTarget).removeClass('prevent');
}, 1000)
});
});
I want to serialize 2 events in my web application. I have change event tied to an input field and click event tied to a button. User sometimes enters value is input field and presses button immediately.
I want that change event should be called before click event.
Both of the events have AJAX calls and I have declared change event AJAX call as synchronous, but this does not help.
EDIT:
Other important details are as follows
I am using jQuery UI autocomplete feature related change event for input field.
Here is the portion of html code along with related javascript code
<!-- I have more than one input fields with class set as code -->
<input type="text" name="code_1" id="code_1" class="code" value=""/>
<input type="text" name="code_2" id="code_2" class="code" value=""/>
<input type="text" name="code_3" id="code_3" class="code" value=""/>
<!-- Here is the clickable button -->
<input type="button" value="Save" class="formButton" id="postCharge"/>
// Here is the javascript code for these items
$(".code").autocomplete({
source: jsHrefRoot+"/ajax/cpt_autocomp.php",
minLength: 3,
delay: 500, // milliseconds - 1s = 1000ms
select: function (event, ui) {
$(this).val(ui.item.id);
return false;
},
change: function (event, ui) {
// Following function has an AJAX call
getCodeDetail($(this));
return false;
}
}).each(function(){
// This part is for rendering each item and not relevant to my question
});
$( "#postCharge" ).click(function(){
// Again there is an AJAX call in this fuction after long logic of input validation
})
Here is one (async) way:
var $codeInputs = $('.code');
var $button = $('#postCharge');
function changeHandler (cb) {
$.ajax({
// ...
complete: function () {
$(this).data('changeHandled', true);
cb();
}
});
}
function clickHandler () {
$.ajax({
// ...
});
}
function checkChanges (cb) {
var $unhandled = $codeInputs.filter(function () {
var hasChanged = $(this).val() !== $(this).data('initialValue');
return hasChanged && !$(this).data('changeHandled');
});
if (!$unhandled.length) return cb();
changeHandler.call($unhandled.first().get(), checkChanges.bind(this, cb));
}
$codeInputs.each(function () {
$(this).data('initialValue', $(this).val());
})
.autocomplete({
// ...
change: function (event, ui) {
changeHandler.call(this.get(), function () {
// Ajax call complete
});
}
});
$button.click(function (e) {
e.preventDefault();
checkChanges(clickHandler.bind(this));
});
I delayed click event to wait for completion of autocomplete change.
function postCharges() {
...
}
$( "#postCharge" ).click(function(e){
e.preventDefault();
setTimeout(postCharges, 1000);
});
change event always fire before click.
var cansubmit =true;
$('text').on('change',function(){
cansubmit = false;
$.ajax({
...
complete:function(){
cansubmit = true;
}
})
}
buildPromise=function(){
new Promise(function(resolve,reject){
var timer = null;
function checkCanSubmit(){
if(cansubmit){
clearInterval(timer);
resolve();
}
}
if(cansubmit)
resolve();
else
timer = setInterval(checkCanSubmit,10);
})
}
$('btn').on('click',function(){
buildPromise().then(function(){
//todo::
})
})
When I click a chat on my site I want the messages to be grabbed from the server so I use an $.post request like so :
$("#friendsDiv").on("click", "#aFriend", function(event){
retrieveMessages();
}
and this is what is in the retrieveMessages function
$.post("PHP/chat.php",
{
action:'retrieveMessages',
last_message: last_message,
conversation_id:conversation_id
},
function(data){
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({ scrollTop: $("#messages")[0].scrollHeight}, 1000);
}
);
The issue is that if the button is clicked very quickly multiple post requests will begin before the last_message is updated, this results in many copies of the same messages being displayed. Is there a way to prevent the button being clicked quickly or stop the post request being processed if another of the same request is already being processed?
EDIT
The #aFreind element is a DIV not a button
Typically in such situation you just disable a button until request is complete. For this you will need to provide a callback function. For example:
$("#friendsDiv").on("click", "#aFriend", function (event) {
// reference the button
var button = this;
// disable the button
this.disabled = true;
// provide a callback to be invoked when post is done
retrieveMessages(function() {
button.disabled = false;
});
});
function retrieveMessages(callback) {
$.post("PHP/chat.php", {
action: 'retrieveMessages',
last_message: last_message,
conversation_id: conversation_id
}, function (data) {
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({
scrollTop: $("#messages")[0].scrollHeight
}, 1000);
// execute callback which enables button again
callback();
});
}
Demo: http://jsfiddle.net/9t8fLdjn/
Your best bet would be to disable the button and then enable it after $.post
$("#friendsDiv").on("click", "#aFriend", function(event) {
$(this).prop('disabled', true); // disable
retrieveMessages();
});
and the retrieveMessage function
$.post("PHP/chat.php", {
action: 'retrieveMessages',
last_message: last_message,
conversation_id: conversation_id
}, function(data) {
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({
scrollTop: $("#messages")[0].scrollHeight
}, 1000);
$(this).prop('disabled', false); // enable it again
});
Instead of using on you could use the one jQuery function and bind the button again in the callback. Se http://api.jquery.com/one/
$("#friendsDiv").one("click", "#aFriend", retrieveMessages });
var retrieveMessages = function(){
$.post("PHP/chat.php", {
...
}).done(function(){
$("#friendsDiv").one("click", "#aFriend", retrieveMessages });
});
};
I thought this is something easy to do but I dont find anything helping me out of this.
I have a function
(function($){
myFunction = function(e){
e.preventDefault();
// do stuff
// load ajax content
// animate and show
}
$('.button').on( 'click', myFunction);
})(jQuery);
now this works but I need to know, wait untill everything is done if someone presses many .buttons in a short time cause there are a few elements with class button
I've tried with promise()
$('.button').on( 'click', function(){
$.when( myFunction() ).done(function() {
alert('finished')
});
});
but that gives me an error e is undefined and
$('.button').on( 'click', myFunction).promise().done(function() {
alert('finisehd');
});
anyone knowing what I'm doing wrong and how I could do it to get it to work?
The most common solution would be to set a variable inside the click handler when myFunction is called and check its state with every call of the click handler.
This could be done somewhere along the lines of this:
(function($){
var wait = false;
myFunction = function(e){
e.preventDefault();
if (wait) {
return;
}
wait = true;
// ...
wait = false;
}
$('.button').on( 'click', myFunction);
})(jQuery);
Your function myFunction expects one argument, when you call myFunction() the argument is missing.
Not tested but it should works:
$('.button').on( 'click', function(e){
$.when( myFunction(e) ).done(function() {
alert('finished')
});
});
In addition to not passing in the e variable. You're using $.when incorrectly.
If you want to have the done function called after myFunction finishes its ajax call. You'll need to return a promise from myFunction.
function myFunction(e) {
return $.Deferred(function(deferred) {
doAjax(function(content) { // callback
deferred.resolve(content);
});
});
}
Now when you do
// inside event handler
$.when(myFunction(e)).done(function(content) {
// whoo!
});
I'm using jQuery in my site and I would like to trigger certain actions when a certain div is made visible.
Is it possible to attach some sort of "isvisible" event handler to arbitrary divs and have certain code run when they the div is made visible?
I would like something like the following pseudocode:
$(function() {
$('#contentDiv').isvisible(function() {
alert("do something");
});
});
The alert("do something") code should not fire until the contentDiv is actually made visible.
Thanks.
You could always add to the original .show() method so you don't have to trigger events every time you show something or if you need it to work with legacy code:
Jquery extension:
jQuery(function($) {
var _oldShow = $.fn.show;
$.fn.show = function(speed, oldCallback) {
return $(this).each(function() {
var obj = $(this),
newCallback = function() {
if ($.isFunction(oldCallback)) {
oldCallback.apply(obj);
}
obj.trigger('afterShow');
};
// you can trigger a before show if you want
obj.trigger('beforeShow');
// now use the old function to show the element passing the new callback
_oldShow.apply(obj, [speed, newCallback]);
});
}
});
Usage example:
jQuery(function($) {
$('#test')
.bind('beforeShow', function() {
alert('beforeShow');
})
.bind('afterShow', function() {
alert('afterShow');
})
.show(1000, function() {
alert('in show callback');
})
.show();
});
This effectively lets you do something beforeShow and afterShow while still executing the normal behavior of the original .show() method.
You could also create another method so you don't have to override the original .show() method.
The problem is being addressed by DOM mutation observers. They allow you to bind an observer (a function) to events of changing content, text or attributes of dom elements.
With the release of IE11, all major browsers support this feature, check http://caniuse.com/mutationobserver
The example code is a follows:
$(function() {
$('#show').click(function() {
$('#testdiv').show();
});
var observer = new MutationObserver(function(mutations) {
alert('Attributes changed!');
});
var target = document.querySelector('#testdiv');
observer.observe(target, {
attributes: true
});
});
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
There is no native event you can hook into for this however you can trigger an event from your script after you have made the div visible using the .trigger function
e.g
//declare event to run when div is visible
function isVisible(){
//do something
}
//hookup the event
$('#someDivId').bind('isVisible', isVisible);
//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
$(this).trigger('isVisible');
});
You can use jQuery's Live Query plugin.
And write code as follows:
$('#contentDiv:visible').livequery(function() {
alert("do something");
});
Then everytime the contentDiv is visible, "do something" will be alerted!
redsquare's solution is the right answer.
But as an IN-THEORY solution you can write a function which is selecting the elements classed by .visibilityCheck (not all visible elements) and check their visibility property value; if true then do something.
Afterward, the function should be performed periodically using the setInterval() function. You can stop the timer using the clearInterval() upon successful call-out.
Here's an example:
function foo() {
$('.visibilityCheck').each(function() {
if ($(this).is(':visible')){
// do something
}
});
}
window.setInterval(foo, 100);
You can also perform some performance improvements on it, however, the solution is basically absurd to be used in action. So...
The following code (pulled from http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/) will enable you to use $('#someDiv').on('show', someFunc);.
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
If you want to trigger the event on all elements (and child elements) that are actually made visible, by $.show, toggle, toggleClass, addClass, or removeClass:
$.each(["show", "toggle", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show"); //No bubbling
});
return result;
}
});
And now your element:
$("#myLazyUl").bind("show", function(){
alert(this);
});
You could add overrides to additional jQuery functions by adding them to the array at the top (like "attr")
a hide/show event trigger based on Glenns ideea:
removed toggle because it fires show/hide and we don't want 2fires for one event
$(function(){
$.each(["show","hide", "toggleClass", "addClass", "removeClass"], function(){
var _oldFn = $.fn[this];
$.fn[this] = function(){
var hidden = this.find(":hidden").add(this.filter(":hidden"));
var visible = this.find(":visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function(){
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function(){
$(this).triggerHandler("hide");
});
return result;
}
});
});
I had this same problem and created a jQuery plugin to solve it for our site.
https://github.com/shaunbowe/jquery.visibilityChanged
Here is how you would use it based on your example:
$('#contentDiv').visibilityChanged(function(element, visible) {
alert("do something");
});
What helped me here is recent ResizeObserver spec polyfill:
const divEl = $('#section60');
const ro = new ResizeObserver(() => {
if (divEl.is(':visible')) {
console.log("it's visible now!");
}
});
ro.observe(divEl[0]);
Note that it's crossbrowser and performant (no polling).
Just bind a trigger with the selector and put the code into the trigger event:
jQuery(function() {
jQuery("#contentDiv:hidden").show().trigger('show');
jQuery('#contentDiv').on('show', function() {
console.log('#contentDiv is now visible');
// your code here
});
});
Use jQuery Waypoints :
$('#contentDiv').waypoint(function() {
alert('do something');
});
Other examples on the site of jQuery Waypoints.
I did a simple setinterval function to achieve this. If element with class div1 is visible, it sets div2 to be visible. I know not a good method, but a simple fix.
setInterval(function(){
if($('.div1').is(':visible')){
$('.div2').show();
}
else {
$('.div2').hide();
}
}, 100);
You can also try jQuery appear plugin as mentioned in parallel thread https://stackoverflow.com/a/3535028/741782
This support easing and trigger event after animation done! [tested on jQuery 2.2.4]
(function ($) {
$.each(['show', 'hide', 'fadeOut', 'fadeIn'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
var result = el.apply(this, arguments);
var _self=this;
result.promise().done(function () {
_self.triggerHandler(ev, [result]);
//console.log(_self);
});
return result;
};
});
})(jQuery);
Inspired By http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
There is a jQuery plugin available for watching change in DOM attributes,
https://github.com/darcyclarke/jQuery-Watch-Plugin
The plugin wraps All you need do is bind MutationObserver
You can then use it to watch the div using:
$("#selector").watch('css', function() {
console.log("Visibility: " + this.style.display == 'none'?'hidden':'shown'));
//or any random events
});
Hope this will do the job in simplest manner:
$("#myID").on('show').trigger('displayShow');
$('#myID').off('displayShow').on('displayShow', function(e) {
console.log('This event will be triggered when myID will be visible');
});
I changed the hide/show event trigger from Catalint based on Glenns idea.
My problem was that I have a modular application. I change between modules showing and hiding divs parents. Then when I hide a module and show another one, with his method I have a visible delay when I change between modules. I only need sometimes to liten this event, and in some special childs. So I decided to notify only the childs with the class "displayObserver"
$.each(["show", "hide", "toggleClass", "addClass", "removeClass"], function () {
var _oldFn = $.fn[this];
$.fn[this] = function () {
var hidden = this.find(".displayObserver:hidden").add(this.filter(":hidden"));
var visible = this.find(".displayObserver:visible").add(this.filter(":visible"));
var result = _oldFn.apply(this, arguments);
hidden.filter(":visible").each(function () {
$(this).triggerHandler("show");
});
visible.filter(":hidden").each(function () {
$(this).triggerHandler("hide");
});
return result;
}
});
Then when a child wants to listen for "show" or "hide" event I have to add him the class "displayObserver", and when It does not want to continue listen it, I remove him the class
bindDisplayEvent: function () {
$("#child1").addClass("displayObserver");
$("#child1").off("show", this.onParentShow);
$("#child1").on("show", this.onParentShow);
},
bindDisplayEvent: function () {
$("#child1").removeClass("displayObserver");
$("#child1").off("show", this.onParentShow);
},
I wish help
One way to do this.
Works only on visibility changes that are made by css class change, but can be extended to watch for attribute changes too.
var observer = new MutationObserver(function(mutations) {
var clone = $(mutations[0].target).clone();
clone.removeClass();
for(var i = 0; i < mutations.length; i++){
clone.addClass(mutations[i].oldValue);
}
$(document.body).append(clone);
var cloneVisibility = $(clone).is(":visible");
$(clone).remove();
if (cloneVisibility != $(mutations[0].target).is(":visible")){
var visibilityChangedEvent = document.createEvent('Event');
visibilityChangedEvent.initEvent('visibilityChanged', true, true);
mutations[0].target.dispatchEvent(visibilityChangedEvent);
}
});
var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
target.addEventListener('visibilityChanged',VisbilityChanedEventHandler});
target.addEventListener('DOMNodeRemovedFromDocument',VisbilityChanedEventHandler });
observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
});
function VisbilityChanedEventHandler(e){console.log('Kaboom babe'); console.log(e.target); }
my solution:
; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = $.fn[ name ];
$.fn[ name ] = function( speed, easing, callback ) {
if(speed == null || typeof speed === "boolean"){
var ret=cssFn.apply( this, arguments )
$.fn.triggerVisibleEvent.apply(this,arguments)
return ret
}else{
var that=this
var new_callback=function(){
callback.call(this)
$.fn.triggerVisibleEvent.apply(that,arguments)
}
var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
return ret
}
};
});
$.fn.triggerVisibleEvent=function(){
this.each(function(){
if($(this).is(':visible')){
$(this).trigger('visible')
$(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
}
})
}
})(jQuery);
example usage:
if(!$info_center.is(':visible')){
$info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
processMoreLessButton()
}
function processMoreLessButton(){
//some logic
}
$( window ).scroll(function(e,i) {
win_top = $( window ).scrollTop();
win_bottom = $( window ).height() + win_top;
//console.log( win_top,win_bottom );
$('.onvisible').each(function()
{
t = $(this).offset().top;
b = t + $(this).height();
if( t > win_top && b < win_bottom )
alert("do something");
});
});
$(function() {
$(document).click(function (){
if ($('#contentDiv').is(':visible')) {
alert("Visible");
} else {
alert("Hidden");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="contentDiv">Test I'm here</div>
<button onclick="$('#contentDiv').toggle();">Toggle the div</button>
<div id="welcometo">Özhan</div>
<input type="button" name="ooo"
onclick="JavaScript:
if(document.all.welcometo.style.display=='none') {
document.all.welcometo.style.display='';
} else {
document.all.welcometo.style.display='none';
}">
This code auto control not required query visible or unvisible control