how to fire window.resize only once? - javascript

Here is my code;
$(window).resize(function() {
if ($(window).width() >= 760) {
$('.sidebar-left').one().css("display", "block")
} else if ($(window).width() <= 760) {
$('.sidebar-left').one().css("display", "none")
}
});
var m = $(".menu");
m.addClass('fa-bars');
m.on('click', function() {
if (m.hasClass('fa-bars')) {
m
.removeClass('fa-bars')
.addClass('fa-times');
$(".sidebar-left").css("display", "block")
} else {
m
.removeClass('fa-times')
.addClass('fa-bars');
$(".sidebar-left").css("display", "none")
}
});
.sidebar-left {
width: 100px;
position: fixed;
background-color: black;
height: 100%;
}
.menu.fa {
display: none;
}
#media handheld,
screen and (max-width: 760px) {
.sidebar-left {
display: none;
width: 100%;
background-color: black;
height: 100px;
}
.menu.fa {
display: inline-block;
font-size: 35px;
color: black;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menu fa"></div>
<div class="sidebar-left"></div>
And a plunk. (may be easier to test here)
So it's just a simple menu. The issue I have is that currently the resize event will run every time the page is resized, so if I have the menu displayed under 760 pixels it will automatically disappear on resize if I have it opened.
If I take the javascript resize function out completely and leave it to the css, the problem is if I open and close the menu in a smaller window, the display will be set to none when I make the window larger again.
I've tried a few other things, but can't seem to think of a way of doing this. The aim is to just to replicate what the $(window).resize function is doing currently, but for that event to fire only once the window has resized past the points.
Hope the problem is explained clearly.
Thanks

You could use jQuery's one() method, which gets activated exactly once:
$(window).one('resize', function() {
if ($(window).width() >= 760) {
$('.sidebar-left').one().css("display", "block")
} else if ($(window).width() <= 760) {
$('.sidebar-left').one().css("display", "none")
}
});
This will solve your question as asked, but i would actually recommend not disabling the resize event and just handling it better, i.e. checking whether it is proper to open/close the sidebar.

Here's a plugin I made, with a resize begin handler, a resize end handler and of course an on resize handler.
(function() {
var resizeEventHandler = function(resizeTarget, _maxResizeWaitTime, onResizeBeginCB, onResizeEndCB, onResizeCB) {
if(resizeTarget){
var resizeTimer = null;
var resizeBegun = false;
var maxResizeWaitTime = _maxResizeWaitTime || 500;
resizeTarget.addEventListener('resize', function() {
if (!resizeBegun) {
if(onResizeBeginCB){
onResizeBeginCB();
}
resizeBegun = true;
}
if(onResizeCB){
onResizeCB();
}
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if(onResizeEndCB){
onResizeEndCB();
}
resizeBegun = false;
}, maxResizeWaitTime);
});
}else{
console.error('No resizeTarget specified!');
}
};
this.resizeEventHandler = resizeEventHandler;
}).call(this);
Call it like this:
function onResizeBegin() {
$("body").append('onResizeBegin<br/>')
}
function onResizeEnd() {
$("body").append('onResizeEnd<br/>')
}
function onResize() {
$("body").append('onResize<br/>')
}
var resizeEventHandler1 = new resizeEventHandler(window, 500, onResizeBegin, onResizeEnd, onResize);
JSfiddle: https://jsfiddle.net/sv52m1y2/3/

Related

Scroll lock for body while mobile menu is open is not working

I have found several other solutions that demonstrate how you can lock scroll behaviour for a website by using CSS overflow property. As such I have implemented this solution and added the overflow: hidden; to the body tag when the menu is open. However when using iOS Safari or Chrome the body is still scrollable.
CSS:
body.opened-drawer {
overflow: hidden !important;
height: 100% !important;
width: 100% !important;
position: fixed !important;
z-index: 0 !important;
}
JS:
timber.openDrawerMenu = function () {
var $mobileMenu = $('.nav-bar'),
$mobileMenuButton = $('#menu-opener'),
$body = $('body');
$mobileMenuButton.addClass('opened');
$mobileMenu.addClass('opened');
$body.addClass('opened-drawer');
// Make drawer a11y accessible
timber.cache.$navBar.attr('aria-hidden', 'false');
// Set focus on drawer
timber.trapFocus({
$container: timber.cache.$navBar,
namespace: 'drawer_focus'
});
// Escape key closes menu
timber.cache.$html.on('keyup.drawerMenu', function(evt) {
if (evt.keyCode == 27) {
timber.closeDrawerMenu();
}
});
}
timber.closeDrawerMenu = function () {
var $mobileMenu = $('.nav-bar'),
$mobileMenuButton = $('#menu-opener'),
$body = $('body');
$mobileMenuButton.removeClass('opened');
$mobileMenu.removeClass('opened');
$body.removeClass('opened-drawer');
// Make drawer a11y unaccessible
timber.cache.$navBar.attr('aria-hidden', 'true');
// Remove focus on drawer
timber.removeTrapFocus({
$container: timber.cache.$navBar,
namespace: 'drawer_focus'
});
timber.cache.$html.off('keyup.drawerMenu');
}
Here you go for the quick fix
body.opened-drawer {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
z-index: 0;
}
Please find the modified script here
function menuDrawerButtons (){
cache.$mobileMenuButton.on('click', function(e) {
e.preventDefault();
if ($(this).hasClass('opened')) {
timber.closeDrawerMenu()
} else {
timber.openDrawerMenu();
}
});
setTimeout(function() {
cache.$mobileMenu.addClass('animate');
}, 500);
}
The solution I came to is more of a hack and less a solution but gets the job done either way. What I did was fix the position on the body when the menu was opened and calculate and set the scrollTop position as the menu was opened or closed.
jQuery:
var tempScrollTop = null;
tempScrollTop = $(window).scrollTop();
$(window).scrollTop(tempScrollTop);
var fixed = document.getElementById('fixed--nav');
fixed.addEventListener('touchmove', function(e) {
e.preventDefault();
}, false);

How do i create a scroll to top button on a single page?

After some decent search time, i still haven't found any information for this specific function but i'm sure it can be done.
The site i'm working with has very short pages albeit one. I created a scroll to top button for this single long page with no problems. I want this button to only work for this individual page but when i load another page on the site i get console errors - 'Uncaught TypeError: Cannot read property 'style' of null at scrollFunction'
This is the function i've attempted to use to check the href of the page:
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (window.location.href.indexOf("portfolio.html")) {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
document.getElementById("scrollButton").style.display = "block";
} else {
document.getElementById("scrollButton").style.display = "none";
}
}
}
Any guidance would be much appreciated.
This is similar to the answer proposed by Sujen K., but has some differences that simplify code clarity and makes things a bit better for performance:
var elementExists = document.getElementById('scrollButton');
// We can skip the page URL check because in theory this
// behavior is desired on any page with the scrollButton
if (elementExists) {
// By moving the onScroll function into the if statement
// it no longer has to check on pages without scrollButton
// We can also simplify how it is set up.
window.onscroll = function () {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
// We can reuse elementExists here for a minor
// performance gain instead of having to get it again.
elementExists.style.display = "block";
} else {
elementExists.style.display = "none";
}
};
}
The answer is simple, your statement will be always considered as true, because of indexOf (see spec) return the index (number) of the first founded occurrence, otherwise will return -1.
You should update your code in way:
if (window.location.href.indexOf("portfolio.html") !== -1) {
Have a look at this solution:
http://jsfiddle.net/neeklamy/RpPEe/
$(document).ready(function () {
$(window).scroll(function () {
if ($(this).scrollTop() > 100) {
$('.scrollup').fadeIn();
} else {
$('.scrollup').fadeOut();
}
});
$('.scrollup').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
});
Also - consider ditching JS and just give your body an ID (id="something"), then have a link point at (href="#something"). It solves the problem with no scripting at all.
Look this solution:
https://jsfiddle.net/9x204t2o/1/
JS:
$(document).ready(function(){
$(window).scroll(function(){
if ($(this).scrollTop() > 100) {
$('.scrollToTop').fadeIn();
} else {
$('.scrollToTop').fadeOut();
}
});
$('.scrollToTop').click(function(){
$('html, body').animate({scrollTop : 0},800);
return false;
});
});
CSS:
.scrollToTop{
width: 100px;
height: 80px;
padding: 10px;
text-align: center;
background: whiteSmoke;
font-weight: bold;
color: #444;
text-decoration: none;
position: fixed;
bottom: 0;
right: 0;
display: none;
background: url(https://cdn3.iconfinder.com/data/icons/iconic-1/32/arrow_up_alt1-512.png) no-repeat;
background-size: 40px;
background-position: 40px 30px;
}
.scrollToTop:hover{
text-decoration:none;
}
HTML:
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
Scroll To Top
[...]
Can help?

Wait for element to be displayed to user

How do I wait for an element to be displayed/seen by the user? I have the following function, but it only checks to see if the element exists and not whether it is visible to the user.
function waitForElementDisplay (selector, time) {
if (document.querySelector(selector) != null) {
return true;
} else if (timeLimit < timeSince) {
return false;
} else {
timeSince += time;
setTimeout(function () {
waitForElementDisplay(selector, time, timeLimit, timeSince);
}, time);
}
}
It's a bit confuse, are you trying a simple "sleep"?
You can wait element load using:
document.querySelector(selector).onload = function() {
// Your code ...
}
Some working snippet, run it:
// Triggering load of some element
document.querySelector("body").onload = function() {
// Setting the timeout and visible to another element
setTimeout(function () {
document.querySelector("#my_element").style.display = "block" /* VISIBLE */
}, 1000);
}
#my_element{
width: 100px;
height: 100px;
background-color: red;
display: none; /* INVISIBLE */
}
<div id="my_element"></div>
If you want to wait time as you have set to the function and the selector which should appear after this time.. You can mind about a simple setTimeout() and CSS.
Run the example below, hope it helps:
// Triggering, in my exemple i've used: WINDOW ONLOAD
window.onload = function() {
waitForElementDisplay("#my_element", 1000);
}
function waitForElementDisplay (selector, time) {
// Check the DOM Node in console
console.log(document.querySelector(selector));
// If it's a valid object
if (typeof document.querySelector(selector) !== "undifined") {
// Setting the timeout
setTimeout(function () {
document.querySelector(selector).style.display = "block" /* VISIBLE */
}, time);
}
}
#my_element{
width: 100px;
height: 100px;
background-color: red;
display: none; /* INVISIBLE */
}
<div id="my_element"></div>
You could use jQuery .ready()
selector.ready(function(){
// do stuff
})

JavaScript function -- call single time with wheel event?

This code nearly works but has a slight problem which is where I'm hoping for your help.
The Goal: This goal of this script is to call the parseScroll(); function one time when the user wheels using the mouse.
The Problem: The code initially works. However, if you wheel with your finger on the mouse mutiple times within short proximilty,
the parseScroll(); function isn't called. It does this because it
hasn't realized that the previous wheel has ended since because of the
debouncing algorithm in place to keep the function from being called a
thousand times.
(Update): I found this article which seems to address what I'm looking for. Could someone help me understand it and recreate it in pure JavaScript? http://demos111.mootools.net/Mousewheel
Side Note: This question is specific to OS X but I would appreciate it
if a windows user could tell me if it is doing what it is supposed to
do in windows since I don't have a windows machine to test it with.
Here is a replica of the script that is giving me problems.
window.addEventListener('load', function() {
var scrollStatus = {
wheeling: false,
functionCall: false
};
var scrollTimer = false;
window.addEventListener('wheel', function(e) {
scrollStatus.wheeling = true;
if (!scrollStatus.functionCall) {
parseScroll(e);
scrollStatus.functionCall = true;
}
window.clearInterval(scrollTimer);
scrollTimer = window.setTimeout(function() {
scrollStatus.wheeling = false;
scrollStatus.functionCall = false;
}, 500);
});
function parseScroll(e) {
//console.log(scrollStatus.functionCall)
console.log(e.deltaY)
if (e.deltaY > 0) {
console.log('scrolled down')
}
if (e.deltaY < 0) {
console.log('scrolled up')
}
}
});
html,
body {
width: 100%;
height: 100%;
background: #333;
overflow: hidden;
color: #fff;
}
Please wheel on your mouse and open your web inspector console to see resulting behavior.
Please ask questions in the comments and revisit the question as I may change the description as I find better ways to describe the problem.
I would like my solution to be in JavaScript.
The problem seems to be that debounce function, as you figured out. All you do is change the millisecond interval, and that should fix it.
NOTE: I took out the HTML and CSS to make things less cluttered. I also edited the JS a bit to make it shorter - hope that isn't a problem!
window.addEventListener('load', function() {
var scrollStatus = {
wheeling: false,
functionCall: false
};
var scrollTimer = false;
window.addEventListener('wheel', function(e) {
scrollStatus.wheeling = true;
if (!scrollStatus.functionCall) {
//parseScroll here
console.log(e.deltaY)
if (e.deltaY > 0) {
console.log('scrolled down')
}
if (e.deltaY < 0) {
console.log('scrolled up')
}
scrollStatus.functionCall = true;
}
window.clearInterval(scrollTimer);
scrollTimer = window.setTimeout(function() {
scrollStatus.wheeling = false;
scrollStatus.functionCall = false;
}, 50); //set this millisecond to your liking
});
});
Edit, Updated
Try defining handler as named function, calling .removeEventListener after parseScroll called
window.addEventListener('load', function() {
var scrollStatus = {
wheeling: false,
functionCall: false
};
function wheel(e) {
scrollStatus.wheeling = true;
if (!scrollStatus.functionCall) {
scrollStatus.functionCall = true;
parseScroll(e);
window.removeEventListener("wheel", wheel, false)
}
window.clearInterval(scrollTimer);
scrollTimer = window.setTimeout(function() {
scrollStatus.wheeling = false;
scrollStatus.functionCall = false;
}, 500);
}
var scrollTimer = false;
window.addEventListener('wheel', wheel, false);
function parseScroll(e) {
//console.log(scrollStatus.functionCall)
console.log(e.deltaY)
if (e.deltaY > 0) {
console.log('scrolled down')
}
if (e.deltaY < 0) {
console.log('scrolled up')
}
}
});
html,
body {
width: 100%;
height: 100%;
background: #333;
overflow: hidden;
color: #fff;
}
Please wheel on your mouse and open your web inspector console to see resulting behavior.

How do I clear this setInterval inside a function?

Normally, I’d set the interval to a variable and then clear it like var the_int = setInterval(); clearInterval(the_int); but for my code to work I put it in an anonymous function:
function intervalTrigger() {
setInterval(function() {
if (timedCount >= markers.length) {
timedCount = 0;
}
google.maps.event.trigger(markers[timedCount], "click");
timedCount++;
}, 5000);
};
intervalTrigger();
How do I clear this? I gave it a shot and tried var test = intervalTrigger(); clearInterval(test); to be sure, but that didn’t work.
Basically, I need this to stop triggering once my Google Map is clicked, e.g.
google.maps.event.addListener(map, "click", function() {
//stop timer
});
The setInterval method returns a handle that you can use to clear the interval. If you want the function to return it, you just return the result of the method call:
function intervalTrigger() {
return window.setInterval( function() {
if (timedCount >= markers.length) {
timedCount = 0;
}
google.maps.event.trigger(markers[timedCount], "click");
timedCount++;
}, 5000 );
};
var id = intervalTrigger();
Then to clear the interval:
window.clearInterval(id);
// Initiate set interval and assign it to intervalListener
var intervalListener = self.setInterval(function () {someProcess()}, 1000);
function someProcess() {
console.log('someProcess() has been called');
// If some condition is true clear the interval
if (stopIntervalIsTrue) {
window.clearInterval(intervalListener);
}
}
the_int=window.clearInterval(the_int);
Simplest way I could think of: add a class.
Simply add a class (on any element) and check inside the interval if it's there. This is more reliable, customisable and cross-language than any other way, I believe.
var i = 0;
this.setInterval(function() {
if(!$('#counter').hasClass('pauseInterval')) { //only run if it hasn't got this class 'pauseInterval'
console.log('Counting...');
$('#counter').html(i++); //just for explaining and showing
} else {
console.log('Stopped counting');
}
}, 500);
/* In this example, I'm adding a class on mouseover and remove it again on mouseleave. You can of course do pretty much whatever you like */
$('#counter').hover(function() { //mouse enter
$(this).addClass('pauseInterval');
},function() { //mouse leave
$(this).removeClass('pauseInterval');
}
);
/* Other example */
$('#pauseInterval').click(function() {
$('#counter').toggleClass('pauseInterval');
});
body {
background-color: #eee;
font-family: Calibri, Arial, sans-serif;
}
#counter {
width: 50%;
background: #ddd;
border: 2px solid #009afd;
border-radius: 5px;
padding: 5px;
text-align: center;
transition: .3s;
margin: 0 auto;
}
#counter.pauseInterval {
border-color: red;
}
<!-- you'll need jQuery for this. If you really want a vanilla version, ask -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="counter"> </p>
<button id="pauseInterval">Pause/unpause</button></p>

Categories