Javascript code not getting executed on initial page load - javascript

I have written a Javascript function for resizing the Carousel according to the screen width. It's doing the job properly but the only issue is that it doesn't get initialized on the initial page load. The Carousel is only present on the homepage and when I visit it for the first time, the code doesn't get executed. However, if I reload the page it does get executed. It even gets executed when I resize my browser window. But I would like it to initialize on the first first load as well. Here's the code:
let carousel = document.querySelector('#carousel');
if (carousel) {
const size = 0.8;
window.addEventListener('resize', () => {
let width = carousel.clientWidth || carousel.offsetWidth;
let carouselHeight = (width * size) + 'px';
carousel.querySelector(".slide").style.height = carouselHeight;
}, false);
}

You're adding a listener, but the callback won't get called unless it is triggered.
You can instead declare the callback as a function, add the listener with the function as callback, and then call the function directly for the initial load.
function resizeCarousel(size) {
let width = carousel.clientWidth || carousel.offsetWidth;
let carouselHeight = (width * size) + 'px';
carousel.querySelector(".slide").style.height = carouselHeight;
}
let carousel = document.querySelector('#carousel');
if (carousel) {
const size = 0.8;
window.addEventListener('resize', () => resizeCarousel(size), false);
resizeCarousel(size);
}

You’re adding an event listener on the page resize. First of all, this should all be wrapped in an on load event listener so you can be sure that the element #carousel is even available. Then, I would execute the resize function manually by maybe defining the function in the on load event function. Then set it for resizing events. I’m on my phone so it’s hard to type an example, for for example:
document.addEventListener("DOMContentLoaded", function(event) {
function resize() { /* Resize Function. */ }
var carousel = document.querySelector('#carousel');
window.addEventListener(“resize”, resize);
resize(); // Call it now as well as onresize.
});

Related

Remove event listener and reset classList toggle on resize

I would like to remove a click event listener on a certain screen size, while resizing browser.
The problem is that the code below works where I refresh the page and desired result is there. However, while resizing the browser, it stays in the state of either being clickable if under the wanted width or being non clickable over the wanted width.
let viewPort = window.innerWidth || document.documentElement.clientWidth;
let dropToggle = document.querySelectorAll(".someparent");
let dropMenu = document.querySelectorAll(".somechild");
for (let i = 0; i < dropToggle.length; i++) {
dropToggle[i].addEventListener('click', function a(event) {
if (viewPort < 786) {
dropMenu[i].classList.toggle("drop");
if (event.dropToggle == 2);
event.stopPropagation();
}
else {
dropToggle.removeEventListener('click', a);
/*update*/
dropMenu[i].classList.remove("drop");
}
/*update*/
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
}, true);
});
}
So basically, I would need the function to kick in when the browser is being resized without refreshing the page. Any help would be appreciated.
EDIT updated code with partial solution.
New problem: The toggle classList.toggle "drop" remains open if not closed on the smaller width. Adding a classList.remove to the "drop" within the else condition does not work either, this actually removes the function entirely on resize. Is there a way to reset the classList.toggle on resize?
You need to update the value of viewPort every time you resize your window. At the moment viewPort is initialized when you load your page but is never reinitialized again. To do this you can add a resize event listener to your window:
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
}, true);
You need to define your event listener call outside of your for loop
& pass the callback as a reference in add/remove event listener method.
Also you need to add window.resize event listener (As shown below)
This code should work fine for you
let dropToggle = document.querySelectorAll(".someparent");
let dropMenu = document.querySelectorAll(".somechild");
function a(event) {
dropMenu[i].classList.toggle("drop");
if (event.dropToggle == 2);
event.stopPropagation();
}
for (let i = 0; i < dropToggle.length; i++) {
window.addEventListener("resize", function() {
viewPort = window.innerWidth || document.documentElement.clientWidth;
if (viewPort < 786) {
dropToggle[i].addEventListener("click", a);
} else {
dropToggle[i].removeEventListener("click", a);
}
});
}
Matchmedia can handle this - and allow javascript functions when the media (window) matches the criteria.
References can be found here (https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) and here (https://www.sitepoint.com/javascript-media-queries/)
Effectively its media queries for javascript. And the syntax is essentially the same as for CSS media queries.
// media query event handler
if (matchMedia) {
const mq = window.matchMedia("(min-width: 768px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
// do what you want when window width is at least 768px
} else {
// do what you want when window width is less than 768px
}
}

Compute div style only when it completes rendering an image

In my script I am loading an image from an array into a div, then I calculate some style elements to be tuned.
The problem is that this works only if I use a timeout function before calculating the styles, like this:
$('#forecastImg').attr('src',get_ImageItemLocation(imageArray[0]));
setTimeout(function(){
var himg= $("#forecastImg").height();
var hest = $("#esterno").height();
var margin= ((hest-himg)/2)-$(".header").height()-$(".forecastdate").height();
if (margin>0){
$("#forecastImg").css('margin-top',(margin+'px'));
}
},240);
How can I get rid of the timeout and be sure that the height() value is correct?
If I remove the timeout, I alwyas get a height()=0 value.
Well the problem here is that the image is not loaded when you're trying do calculate the margin, that's why $('#forecastImg').height() is not returning the expected height when you try to make the calculations right away (in your case, you're doing a wait for the loading with a setTimeout)
However, you can use $().load method instead of a unreliable setTimeout to consistently run your calculations after the loading of the image. To do that, you must first bind the .load callback method with those calculations and only then change the src value of it, otherwise the image might load immediately without calling our .load callback:
$('#forecastImg')
.one('load', function () {
var himg = $("#forecastImg").height(),
hest = $("#esterno").height(),
margin = ((hest-himg) / 2) - $(".header").height() - $(".forecastdate").height();
if (margin > 0) {
$("#forecastImg").css('margin-top',(margin+'px'));
}
})
.attr('src', get_ImageItemLocation(imageArray[0]));
You need to wait for the image has loaded, so the timeout is correct, but if you would like to use a different solution, you can use load event instead:
$("#forecastImg").one("load", function() {
var himg= $(this).height();
var hest = $("#esterno").height();
var margin= ((hest-himg)/2)-$(".header").height()-$(".forecastdate").height();
if (margin>0){
$("#forecastImg").css('margin-top',(margin+'px'));
}
});
try the load event of JQuery
$('#forecastImg').load(function() {
var himg = $("#forecastImg").height();
var hest = $("#esterno").height();
var margin = ((hest-himg)/2)-$(".header").height()-$(".forecastdate").height();
if (margin > 0) {
$("#forecastImg").css('margin-top',(margin+'px'));
}
});

Updating global variable on scroll event attached to a DOM element

I've got a situation where I want a variable to be updated when scrolling inside a <div>. There is a series of other things which will happen depending on this variable updating, so I don't want to wrap it inside the scroll event. Is there a way to avoid that?
Here is my JS:
var scrollEl = document.getElementById("scrollEl");
var scrollElWidth = scrollEl.offsetWidth;
var scrolled = 0;
var updater = function(updated) {
scrolled = Math.round(updated);
return scrolled;
}
scrollEl.addEventListener("scroll", function() {
var percentage = 100 * scrollEl.scrollLeft / (scrollEl.scrollWidth - scrollElWidth);
//This works
console.log(updater(percentage));
});
//This doesn't
console.log('Updated scroll variable: ', scrolled);
Here is a fiddle: https://jsfiddle.net/0u4fp0yv/

Initializing a plugin AFTER a foreach loop

So I'm trying to implement stellar.js but it must be initialized after an each loop is finished. The loop must add data attributes to the images that are going to be made parallax by the plugin.
The images are in a list:
<ul>
<li class="item">
<div class="item-image" data-stellar-background-ratio="0.7" data-image="http://picjumbo.picjumbocom.netdna-cdn.com/wp-content/uploads/IMG_7706-1300x866.jpg"></div>
</li>
...
</ul>
I must add data-stellar-vertical-offset attribute to each of them that will offset the image by half of its height, so it can be vertically centered initially.
Here is the JS:
/* Inserting the background image */
$('.item-image').each(function () {
var $this = $(this);
$this.css('background-image', 'url(' + $this.data('image') + ')');
})
/* Creating loop that will run as many times as items are in there */
var items = $('.item-image').length;
var currentItem = 0;
$('.item-image').each(function () {
var $this = $(this);
/* Taking the origin height, halving it and putting it as offset so the image can be vertically aligned */
var img = new Image();
img.src = $(this).data('image');
img.onload = function () {
var H2 = this.height;
$this.attr('data-stellar-vertical-offset', -(H2 / 2));
}
currentItem++;
/* Initializing the plugin after every item is looped */
if (currentItem >= items) {
$.stellar();
}
})
However when the plugin is initialized it isn't using the data attribute. If it's put in a timeout like this:
if (currentItem >= items) {
setTimeout(function () {
$.stellar();
}, 10)
}
.. it works but it seems to me like an ugly hack. Is there a better way for this to be done?
Here is a jsfiddle: http://jsfiddle.net/9f2tc/1/
I believe what you want is to initialize stellar once after all the images have been downloaded. The simplest approach is to check each time in the onload handler:
img.onload = function () {
var H2 = this.height;
$this.attr('data-stellar-vertical-offset', -(H2 / 2))
if (++currentItem === items) {
$.stellar();
}
}
jsfiddle: http://jsfiddle.net/X6e9n/2/
However, there are issues with the onload event not firing for images in certain cases. See the caveats section on the jQuery page: http://api.jquery.com/load-event/ The problems listed apply to the load event itself not just jQuery's .load() See Javascript callback for knowing when an image is loaded for solutions. The first answer notes the handler should be attached before the src attribute is set, which you don't do here, but it doesn't seem to be a problem for me in this case.

JavaScript/jQuery onmouseover problem

I want that when mouse is over an image, an event should be triggered ONCE, and it should be triggered again only after mouse is out of that image and back again, and also at least 2 seconds passed.
My current function is called continuously (refreshcash) if I leave the mouse over my image
<img src="images/reficon.png" onmouseover="refreshcash()" onmouseout="normalimg()" id="cashrefresh"/>
function refreshcash() {
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function normalimg() {
$("#cashrefresh").attr("src","images/reficon.png");
}
code update
This code seems to have a bug,but the algorithm is kinda logical
<script type="text/javascript">
var canhover = 1;
var timeok = 1;
function redotimeok() {
timeok = 1;
}
//
function onmenter()
{
if (canhover == 1 && timeok == 1)
{
enter();
canhover = 0;
}
}
//
function onmleave()
{
leave();
canhover = 1;
setTimeout(redotimeok(), 2000);
leave();
}
//
$('#cashrefresh').hover(onmenter(),onmleave());
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
}
</script>
Try the hover:
$('#cashrefresh').hover(function(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}, function(){
$("#cashrefresh").attr("src","images/reficon.png");
});
And your image should look like:
<img src="images/reficon.png" id="cashrefresh"/>
Update:
Modify your code like this:
var e = null;
var l = null;
$('#cashrefresh').hover(function(){
e = setTimeout(enter, 2000)
}, function(){
l = setTimeout(leave, 2000)
});
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
clearTimeout(e);
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
clearTimeout(l);
}
Do you have the images cached in some way? If you replace them by their src attribute without specifying width/height elsewhere (best would be CSS) or having them readily available then the hovered box (img element) will collapse into a smaller (or no) box until the image has been loaded far enough for the browser to know the correct dimensions of the image to resize the box (which may affect other elements being adjusted to the image). The exact effect depends on the browser but you may lose the hover state causing the call of your mouseout function.
I assume that both images are the same size, so if you didn't already, you could try adding the dimensions to your CSS for #cashrefresh and see if that fixes the problem.
For the delay I would recommend using the jQuery timers plugin (or a similar one) which eases handling of timers compared to doing it on your own. You would probably want to give your timers names and try to stop older ones before you add the next one.

Categories