I am getting an id that is not addressable by jquery ("#"+id).something .
At document start I have a :
var g_justClicked = '';
$.ajaxSetup({
beforeSend:function(event){
if(g_justClicked) {
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
};
var wOffset = $('#'+g_justClicked).offset();
$('#loading').show();
},
complete:function(){
$('#loading').hide();
}
});
At document end I have another script (all elements with class spinner should set the global variable 'g_justClicked'):
$(document).ready(function () {
$('.spinner').click(function() {
g_justClicked = $(this).attr('id');
console.log('.spinner.click: g_justClicked='+g_justClicked);
});
This works fine, the variable is set and displayed correctly in ajaxSetup.
BUT: referencing it in tagName= or in wOffset = with
$('#'+g_justClicked).
results in
"TypeError: wOffset/tagName is undefined"
Note: all ids start with several characters, t.e. "boxshow12345" is a typical id.
What am I doing wrong?
I think was able to reproduce your scenario here: https://jsfiddle.net/mrlew/qvvnjjxn/3/
The undefined in your console.log is because you're accessing an inexistent jQuery property: .tagName. This property is only available to native HTML Element.
To retrieve the tag name from a jQuery Object, you should use: .prop("tagName"), or access the property accessing the native element with $('#'+g_justClicked)[0].tagName
So, if you change
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
to:
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).prop("tagName"));
Will successfully log: g_justClicked=boxshow12345 tagName=BUTTON, as expected.
Note: In order to your logic work, you have to click .spinner first.
Your problem is that your ajax setup runs regardless of whatever you do in the click handler, and it runs before you even setup that handler. The initial value for g_justClicked is empty string, and this is what it tries to access in $('#'+g_justClicked), hence the error.
If you want to click the spinner and then pass the id to the beforeSend, do it like this:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax
_setupAjax( g_justClicked );
});
});
function _setupAjax(g_justClicked) {
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
UPDATE
If you don't want a separate function, just move your ajax setup into the click handler:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax setup
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
});
});
OK #mrlew.
Answer: I tried your .prop appoach, but still got "undefined". Now back to the roots:
The goal is to get the id of any element that was clicked to modify the busy indicators position, while ajax is running. Newly I am back to my original approach, without global variable and parameter passing:
$(document).ready(function () {
$('.spinner').click(function() {
_setupAjax();
});
});
which works, and:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
wJustClicked = $(this).attr('id'); /// <- that doesnt work!
console.log("_setupAjax wJustClicked="+wJustClicked);
console.log('_setupAjax tagName=' + $('#' + wJustClicked).prop("tagName"));
....defining css based on id (no problem)..
which yields "undefined" twice. I tried so many ways to get that f.... id.
#mrlew
thanks a lot for your help. Meanwhile I found the solution. All trouble came from a timing problem. Here is what works (for all DIV, SPAN and IMG of class=spinner and having an id:
$(document).ready(function () {
_setupAjax();
$('.spinner').click(function() {
wJustClicked = $(this).attr('id');
if(wJustClicked == null) alert('Id missing on item clicked');
console.log('.spinner.click! id='+wJustClicked);
var wOffset = $('#' + wJustClicked).offset();
var xPos = Math.round(wOffset.left) + 8;
var yPos = Math.round(wOffset.top) + 4;
console.log(wJustClicked+' offset left='+wOffset.left+' top='+wOffset.top+' xPos='+xPos+' yPos='+yPos);
wDiv = 'loading';
$('#'+wDiv).css('left',xPos);
$('#'+wDiv).css('top',yPos);
});
and the js function:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
A strange thing remained (I have firebug installed), which I have solved with Math.round: the x and y position come overdetailed like 170.5134577 and 434.8768664 ?!?
I can live with that. But where does this pseudo precision come from?
Again thanks a lot to keep my hope upright.
I generate a dropdownList dynamicly with jquery Ajax , generated dropdown's id
is specificationAttribute . I want create add event for new tag was generated (specificationAttribute) , to do this I created Belowe script in window.load:
$(document).on('change', '#specificationattribute', function () {
alert("Clicked Me !");
});
but it does not work .
I try any way more like click , live but I cant any result.
jsfiddle
Code from fiddle:
$(window).load(function () {
$("#specificationCategory").change(function () {
var selected = $(this).find(":selected");
if (selected.val().trim().length == 0) {
ShowMessage('please selecet ...', 'information');
}
else {
var categoryId = selected.val();
var url = $('#url').data('loadspecificationattributes');
$.ajax({
url: url,
data: { categoryId: categoryId, controlId: 'specificationattribute' },
type: 'POST',
success: function (data) {
$('#specificationattributes').html(data);
},
error: function (response) {
alert(response.error);
}
});
}
});
$(document).on('change', '#specificationAttribute', function () {
alert("changed ");
});
}
Your fiddle has syntax errors. Since a dropdownlist generates a select, let's use one.
For my answer I used THIS HTML, more on this later: things did not match in your code
<select id="specificationAttribute" name="specificationAttribute">
</select>
Code updated: (see inline comments, some are suggestions, some errors)
$(window).on('load', function() {
$("#specificationCategory").on('change',function() {
var selected = $(this).find(":selected");
// if there is a selection, this should have a length so use that
// old: if (selected.val().trim().length == 0) {
if (!selected.length) { // new
// NO clue what this is and not on the fiddle so commented it out
// ShowMessage('please selecet ...', 'information');
alert("select something a category");// lots of ways to do this
} else {
var categoryId = selected.val();
var url = $('#url').data('loadspecificationattributes');
$.ajax({
url: url,
data: {
categoryId: categoryId,
controlId: 'specificationattribute'
},
type: 'POST',
success: function(data) {
// THIS line id does not match my choice of specificationAttribute so I changed it
$('#specificationAttribute').html(data);
},
error: function(response) {
alert(response.error);
}
});
}
});
// THIS should work with the markup I put as an example
$(document).on('change', '#specificationAttribute', function() {
alert("changed ");
});
});// THIS line was missing parts
#Uthman, it might be the case that you have given different id to select and using wrong id in onchange event as i observed in the jsfiddle link https://jsfiddle.net/a65m11b3/4/`
success: function (data) {
$('#specificationattributes').html(data);
},and $(document).on('change', '#specificationAttribute', function () {
alert("changed ");
}); $(document).on('change', '#specificationAttribute', function () {
alert("changed ");
});.
It doesnt work because at the moment of attaching event your html element doesnt existi yet.
What you need are delegated events. Basically, you attach event to parent element + you have selector for child (usually by classname or tagname). That way event fires for existing but also for elements that meet selector added in future.
Check documentation here:
https://api.jquery.com/on/#on-events-selector-data-handler
Especially part with this example:
$( "#dataTable tbody" ).on( "click", "tr",
function() {
console.log( $( this ).text() );
});
I am really new to JS/JQuery, I cant figure out how to keep this code D.R.Y, if its even possible at all I don't know. I am using JQuery for an on hover effect with an image. Box1 being the div and the img_hover_effect being the overlay on hover.
JS:
$('.box1').hover(function () {
$('.img_hover_effect').fadeIn(500);
}, function () {
$('.img_hover_effect').fadeOut(400);
});
$('.box2').hover(function () {
$('.img_hover_effect_2').fadeIn(500);
}, function () {
$('.img_hover_effect_2').fadeOut(400);
});
$('.box3').hover(function () {
$('.img_hover_effect_3').fadeIn(500);
}, function () {
$('.img_hover_effect_3').fadeOut(400);
});
Use data attribute on .box elements to store the target element selector.
Also, add a same class to all the .boxn elements to bind event on all the elements.
HTML:
<div class="mybox box" data-target=".img_hover_effect"></div>
<div class="mybox box2" data-target=".img_hover_effect_2"></div>
<div class="mybox box3" data-target=".img_hover_effect_3"></div>
Javascript:
$('.mybox').hover(function () {
$($(this).data('target')).fadeIn(500);
}, function () {
$($(this).data('target')).fadeOut(400);
});
You can use a loop to do that.
An anonymous function inside the loop is used to prevent breakage jQuery events, try:
for(var i = 1; i <= 3; i++){
(function(num){
$('.box' + num).hover(function() {
$('.img_hover_effect' + (num == 1 ? "" : num)).fadeIn(500)
}, function(){
$('.img_hover_effect' + (num == 1 ? "" : num)).fadeOut(400)
})
})(i)
}
Demo
How about:
function hover(div, overlay) {
$(div).hover(function() {
$(overlay).fadeIn(500);
}, function() {
$(overlay).fadeOut(400);
});
}
Then you can call it for each div and overlay as follows:
hover('.box1', '.img_hover_effect');
So you have a function which can be used for fadeIn of 500ms and fadeOut of 400ms. If you would need different fadeIn- and fadeOut-intervalls, you could even adjust the function with these as additional parameters.
Try combining selectors
$(".box1, .box2, .box3").hover(function (e) {
$(".img_hover_effect_" + e.target.className.slice(-1)).fadeIn(500);
}, function (e) {
$(".img_hover_effect_" + e.target.className.slice(-1)).fadeOut(400);
});
I'm trying to rewrite some script. This script takes some data from data attributes and rebuild block with them. All was alright, but I need to do it via AJAX. Here my modified script:
(function($){
jQuery.fn.someItem = function()
{
var make = function() {
var _$this = $(this);
var $thumb = _$this.find('.thumb');
function init()
{
$thumb.on('click', function()
{
if (!$(this).hasClass('active')) setNewActiveItem($(this));
return false;
});
}
function setNewActiveItem($newItem)
{
$.ajax({
url: '/ajax-item?id=' + $newItem.data('id'),
type: 'GET',
success: function(response)
{
_$this.replaceWith(response);
**init();**
}
});
}
init();
};
return this.each(make);
};
})(jQuery);
All working fine, but after Ajax call and block replaced, I can't apply ajax-call in modified block again. I guess that I need to reinit "init()" function after "replaceWith()", but how to do it? Thank you for help.
You need to use a delegated event handler in the init() when attaching your click event to the .thumb elements. Try this:
var make = function() {
var _$this = $(this);
function init() {
_$this.on('click', '.thumb', function() {
if (!$(this).hasClass('active'))
setNewActiveItem($(this));
return false;
});
}
function setNewActiveItem($newItem) {
$.ajax({
url: '/ajax-item?id=' + $newItem.data('id'),
type: 'GET',
success: function(response) {
_$this.replaceWith(response);
}
});
}
init();
};
This works by assigning the click handler to the parent element and inspecting the click event as it bubbles up the DOM. It means that you can append any .thumb element at any time and not have to re-assign any new click handlers as the one defined on the parent will catch all.
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