I'm using the jQuery plugin PowerTip to show tooltips on hover. I initialize it with $('.tooltip').powerTip() and this works great on already loaded content, but if I dynamically load <div class="tooltip" data-powertip="Hey">Hey</div>, I have to run the $('.tooltip').powerTip() function again, which seems like a waste, especially if I have hundreds of these. Is it possible to do something like this? :
1)
$(document).powerTip('.tooltip', {})
or
2)
$(document).on('mouseover', '.tooltip', function(e) {
$(this).powerTip()
});
The logic seems sound the only issue is you might need a callback function to trigger the popup because triggering the popup and initialising it happen at the same time (which could be problematic)
$('body').on('mouseenter','.tooltip', function(event) {
$(event.target).powerTip();
var delay = 250; // 1/4 of a second
setTimeout(() => {
$(event.target).tooltip('show')
}, delay);
});
Related
I have a situation where I must wait for a Specific image to load, and then either swap out its src, or locate the next image and hide/show it.
What I need to happen is show a placeholder image (silhouette) until its main image is ready, and then hide the silhouette and show the main image. Very common stuff.
Problem is this jquery function does not fire on a new tab, or window... but if I hit f5 it works perfectly... but then again I open a new tab, and it wont fire until I hit f5.
CSS:
.staffImage1, .staffImage2, .staffImage3, .staffImage4, .staffImage5 { display: none; }
Jquery:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5')
.load(function () {
$(this).next('.sillhouette').hide();
$(this).show();
console.log("function fired")
})
I get the log message only after refresh.
Something to be aware of is I am using the "First 14k" method to increase page speed, so maybe jquery just is not ready when the images are initially loaded the first time, but are cached and work after f5?
Each image must wait until its fully loaded, they are in a slider, so I need to show the first slides image as soon as its ready,I cannot wait until all 5 images are ready, as that would slow down the first slides image.
Any advice is appreciated, thank you
This structure:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5').load(...)
does not work to notify you when all the images have been loaded. .load() only works on a single image at a time. And, if the images are cached, they may already have finished loading before your jQuery even runs so you would miss the load event entirely.
The simplest work-around is to use the window load event when all page resources have finished loading:
$(window).load(function() {
// all images are loaded here
});
It is also possible to monitor just those 5 images, but that is more work. I've written code to do this before so I'll see if I can find that prior code.
Here's a jQuery plug-in function that monitors just specific images. It will call its callback when all the images in the jQuery object are loaded:
// call the callback when all images have been loaded
// if all images are already loaded or there were no images in the jQuery
// object, then the callback will be called immediately
jQuery.fn.imgsLoaded = function(fn) {
var cntRemaining = 0;
function checkDone() {
if (cntRemaining === 0) {
fn();
}
}
function imgDone() {
--cntRemaining;
checkDone();
// remove event handlers to kill closure when done
$(this).off("load error abort", imgDone);
}
this.each(function() {
if (!this.tagName.toLowerCase() === "img" && !this.complete && this.src) {
++cntRemaining;
$(this).on("load error abort", imgDone);
}
});
checkDone();
return this;
}
You could use it like this:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5').imgsLoaded(function () {
$(this).next('.sillhouette').hide();
$(this).show();
console.log("function fired")
});
Working demo: http://jsfiddle.net/jfriend00/zaoweyoo/
Write jquery code
'$(document).ready(function(){
//your code
});'
I have tabs logic that load html templates inside a wrapper. That's works fine, but I included an animation that animate height of the tab wrapper when tab is switched.
The problem is the following: When a template contains <img src="/some-image.png"> the $('#tab-content').load('template-url', function() {...}) callback function sometimes is executed before the browser show the images. And my animation is not working correctly.
Code example (jsFiddle):
var currentHeight = $contentHolder.height();
$contentHolder.load(path, function() {
$contentHolder.stop();
function animateHeight() {
var loadedContentHeight = $contentHolder.css('height', 'auto').height();
$contentHolder.height(currentHeight);
$contentHolder.animate({
height: loadedContentHeight
}, 800, 'linear');
}
animateHeight();
});
I tried to set little timeout, but it's not working every time. If I set more that 300ms timeout, It feels like tabs are changed too slow.
I tried to execute the animation when $('img').load(function() {}) is fired, but with no luck.
This bug occurs most often when the web page is fully refreshed and each tab content loading for first time.
The image load event is kind of broken. To know when images are loaded you will have to observe the DOM for changes. Then on every change, you have to fetch all the new images and add the onload event to them from the callback. To prevent checking each element every time, once they've been loaded you could mark them as such by adding a data-loaded="true" property for instance.
One way to listen to DOM changes is the MutationObserver event. This is supported by all modern browsers and IE11.
A better supported solution (IE9 and up) can be found in this answer: Detect changes in the DOM. I will not repeat it here (but it's included in the demo below).
On every DOM change first you check for images without the data-loaded attribute that are already loaded anyway (this could happen when an image was still in the browser's cache) by checking element.complete. If so, fire the callback function and add the attribute to it.
If .complete is not the case, add an onload event to them that also fires the callback once it is loaded.
In your case you only want to fire your callback when all images are loaded, so I added a check if there's still images without the data-loaded attribute. If you remove that if-clause your callback would run after each image is loaded.
// Observe the DOM for changes
observeDOM(document.body, function(){
checkNewImages();
});
var checkNewImages = function() {
var images = $('img:not([data-loaded]').each(function() {
addImageLoadedEvent( this );
});
}
var addImageLoadedEvent = function(img) {
if (img.complete) {
onImageLoaded(img);
} else {
$(img).on('load', function() {
onImageLoaded(this);
});
}
}
// The callback that is fired once an element is loaded
var onImagesLoaded = function(img) {
$(img).attr('data-loaded', 'true');
if($('img:not([data-loaded])').length === 0) {
// YourCallbackHere();
}
}
DEMO: fire event on all images loaded
You can call your animateHeight function as each image in the loaded HTML is in turn loaded. You can expand this selection if you have other objects like videos.
// Call animateHeight as each image loads
var items = $('img', $contentHolder);
items.bind('load', function(){
animateHeight();
});
Updated demo: http://jsfiddle.net/jxxrhvvz/1/
I'm trying to play a sound every time a user gets a new notification. The way I am loading the notifications on my page is simple:
(function($)
{
$(document).ready(function()
{
var $container = $("#noti");
$container.load("notify.php");
var refreshId = setInterval(function()
{
$container.load('notify.php');
}, 1000);
});
})(jQuery);
This works by updating a div container with whatever number the PHP code sends out. it retries every second (probably not the most efficient way, but it works).
I have another piece of code that checks when the div content changes, then creates an alert box (which I will change to playing a sound when the script is done):
var myElement = document.getElementById('noti');
if(window.addEventListener) {
// Normal browsers
myElement.addEventListener('DOMSubtreeModified', contentChanged, false);
} else
if(window.attachEvent) {
// IE
myElement.attachEvent('DOMSubtreeModified', contentChanged);
}
function contentChanged() {
// this function will run each time the content of the DIV changes
alert("js is working");
}
This script works, however it also creates an alert or the first loading of the notifications. This is because it starts of as an empty div, then it loads the data, which sets off this alert script. The only way I could think about going round this is delaying the script from loading for a couple of seconds whilst the AJAX script does its business.
Does anyone know a way I could delay this second script from doing anything for the first few seconds after page load, or perhaps a better way about going round this?
Instead of doing that, use a custom event which you trigger when load finishes:
var refreshId = setInterval(reloadContainer, 1000)
function reloadContainer() {
$container.load('notify.php', function success() {
$container.trigger('loaded')
})
}
$(myElement).on('loaded', contentChanged)
I have a question about a Javascript-file I've made. It makes sure hyperlinks open in a div and not in a new tab. However, I've also made a very simple text-inclusion to show while the page is loading.
$(document).ready(function () {
$('a').on('click', function(e){
e.preventDefault();
var page_url = $(this).prop('href');
var loading =
$('#content')
.html('<h2>The page is loading. A second please.</h2>')
.load(page_url);
});
});
However, some pages are considerably loading faster than others. In other words, in some pages it's very useful to have this script, but when a page is loading immediately, it's just simply very annoying.
Is it possible to measure the time that the 'load' takes, and accordingly, display html or not? (I was thinking about something like: "If time-loading>1000 .html('blabla') / Else").
You can do something like that:
var timer = setTimeout(function() {
$('#content').html('<h2>The page is loading. A second please.</h2>');
timer = null;
}, 1000);
$('#content').load(page_url, function() {
if (timer) {
clearTimeout(timer);
}
});
For fellow googlers, I combined the comments and the answer above to provide a solution. What I did was the following: instead of not displaying the loading message if the page was loading within a second, I made sure it was at least displaying at least a second:
$(document).ready(function () {
$('a').on('click', function(e){
e.preventDefault();
$('#content').html("<div id='status' class='status'></div>");
$('#status').html('<h2>The page is loading. A second please.</h2>');
var page_url = $(this).prop('href');
var loadingMsg = setTimeout(function(){
$('#content').load(page_url, function (){
clearTimeout(loadingMsg);
$('#status').html();
});
},1000);
});
});
The reasons why I did this, is because I couldn't get the timeout-function consistent. Sometimes it worked perfectly, but sometimes the screen just froze and nothing was displayed until the page loaded. Now, it is displayed at least a second, and if the loading takes more, it will be displayed until the page loads.
Thanks for your answers and I hope this helps for people with a similar problem!
The title of the question expresses what I think is the ultimate question behind my particular case.
My case:
Inside a click handler, I want to make an image visible (a 'loading' animation) right before a busy function starts. Then I want to make it invisible again after the function has completed.
Instead of what I expected I realize that the image never becomes visible. I guess that this is due to the browser waiting for the handler to end, before it can do any redrawing (I am sure there are good performance reasons for that).
The code (also in this fiddle: http://jsfiddle.net/JLmh4/2/)
html:
<img id="kitty" src="http://placekitten.com/50/50" style="display:none">
<div>click to see the cat </div>
js:
$(document).ready(function(){
$('#enlace').click(function(){
var kitty = $('#kitty');
kitty.css('display','block');
// see: http://unixpapa.com/js/sleep.html
function sleepStupidly(usec)
{
var endtime= new Date().getTime() + usec;
while (new Date().getTime() < endtime)
;
}
// simulates bussy proccess, calling some function...
sleepStupidly(4000);
// when this triggers the img style do refresh!
// but not before
alert('now you do see it');
kitty.css('display','none');
});
});
I have added the alert call right after the sleepStupidly function to show that in that moment of rest, the browser does redraw, but not before. I innocently expected it to redraw right after setting the 'display' to 'block';
For the record, I have also tried appending html tags, or swapping css classes, instead of the image showing and hiding in this code. Same result.
After all my research I think that what I would need is the ability to force the browser to redraw and stop every other thing until then.
Is it possible? Is it possible in a crossbrowser way? Some plugin I wasn't able to find maybe...?
I thought that maybe something like 'jquery css callback' (as in this question: In JQuery, Is it possible to get callback function after setting new css rule?) would do the trick ... but that doesn't exist.
I have also tried to separte the showing, function call and hiding in different handlers for the same event ... but nothing. Also adding a setTimeout to delay the execution of the function (as recommended here: Force DOM refresh in JavaScript).
Thanks and I hope it also helps others.
javier
EDIT (after setting my preferred answer):
Just to further explain why I selected the window.setTimeout strategy.
In my real use case I have realized that in order to give the browser time enough to redraw the page, I had to give it about 1000 milliseconds (much more than the 50 for the fiddle example). This I believe is due to a deeper DOM tree (in fact, unnecessarily deep).
The setTimeout let approach lets you do that.
Use JQuery show and hide callbacks (or other way to display something like fadeIn/fadeOut).
http://jsfiddle.net/JLmh4/3/
$(document).ready(function () {
$('#enlace').click(function () {
var kitty = $('#kitty');
// see: http://unixpapa.com/js/sleep.html
function sleepStupidly(usec) {
var endtime = new Date().getTime() + usec;
while (new Date().getTime() < endtime);
}
kitty.show(function () {
// simulates bussy proccess, calling some function...
sleepStupidly(4000);
// when this triggers the img style do refresh!
// but not before
alert('now you do see it');
kitty.hide();
});
});
});
Use window.setTimeout() with some short unnoticeable delay to run slow function:
$(document).ready(function() {
$('#enlace').click(function() {
showImage();
window.setTimeout(function() {
sleepStupidly(4000);
alert('now you do see it');
hideImage();
}, 50);
});
});
Live demo
To force redraw, you can use offsetHeight or getComputedStyle().
var foo = window.getComputedStyle(el, null);
or
var bar = el.offsetHeight;
"el" being a DOM element
I do not know if this works in your case (as I have not tested it), but when manipulating CSS with JavaScript/jQuery it is sometimes necessary to force redrawing of a specific element to make changes take effect.
This is done by simply requesting a CSS property.
In your case, I would try putting a kitty.position().left; before the function call prior to messing with setTimeout.
What worked for me is setting the following:
$(element).css('display','none');
After that you can do whatever you want, and eventually you want to do:
$(element).css('display','block');