Why doesn this JQuery resize work? - javascript

I am trying to get a script to run only if the viewport is below 1025. Then on resize, if if the screen size is increased either ignore or run the script. At present it runs whatever screen size.
$(document).ready(function() {
$(window).resize(function() {
if ($(window).width() < 1025) {
var $caseStudies = $('.case-study');
$('.pagination div').on('click', function() {
$caseStudies.css("position", "absolute");
$caseStudies.eq($(this).index()).css("position", "relative");
});
}
else {
// ELEMENT IS ABSOLUTE
}
});
});

There's nothing in your code to remove the handler you set up in the < 1025 case when the window is no longer < 1025 in size. You have to explicitly remove the handler. Probably the easiest way is with an event class. You'll also need a marker to indicate whether the handler has been attached. See *** comments:
$(document).ready(function() {
var hasHandler = false;
$(window).resize(function() {
if ($(window).width() < 1025) {
// *** Add handler if we don't already have it
if (!hasHandler) {
hasHandler = true;
var $caseStudies = $('.case-study');
$('.pagination div').on('click.positioner', function() {
// *** Note ------------------^^^^^^^^^^^
$caseStudies.css("position", "absolute");
$caseStudies.eq($(this).index()).css("position", "relative");
});
}
}
else {
// If we ever added a handler...
if (hasHandler) {
hasHandler = false;
// *** Remove it
$('.pagination div').off('click.positioner');
// *** Make them all relative again
$('.case-study').css("position", "relative");
}
}
});
});
In a comment you've said:
... this script only seems to work after I resize the browser. I would need it to work if the browser was less than 1025 but detect a resize, if resized
Then you'd simply put the code in a function and call that function both from ready (on page load) and in response to resize:
$(document).ready(function() {
var hasHandler = false;
function handlePositioning() {
if ($(window).width() < 1025) {
// *** Add handler if we don't already have it
if (!hasHandler) {
hasHandler = true;
var $caseStudies = $('.case-study');
$('.pagination div').on('click.positioner', function() {
// *** Note ------------------^^^^^^^^^^^
$caseStudies.css("position", "absolute");
$caseStudies.eq($(this).index()).css("position", "relative");
});
}
}
else {
// If we ever added a handler...
if (hasHandler) {
hasHandler = false;
// *** Remove it
$('.pagination div').off('click.positioner');
// *** Make them all relative again
$('.case-study').css("position", "relative");
}
}
}
handlePositioning();
$(window).resize(handlePositioning);
});
(Or you can add .trigger("resize") at the end of the .on call in the first code block above to trigger the event after adding it, but that's always seemed hacky to me...)

Related

Side navigation menu responsive class to hide on window resize

Hey stackoverflow community!
I have a small issue regarding this JS logic to add a class name to my body tag to hide the side navigation menu upon window resizing. Let me try to explain the issue as clearly as I can. Currently I'm using a UI template by creativetime called Argon. The page when loaded on a full scaled width looks like this:
When I resize the window after the page has loaded it looks like this:
But when I refresh the page, the side navigation is no longer there as how it should be, which is like this:
After refreshing the page, resizing the window thereafter makes the side navigation to hide as it should. The sidenav just doesn't go hidden on first page load for some reason.
The JS for this is as follows:
var Layout = (function() {
function pinSidenav() {
$('.sidenav-toggler').addClass('active');
$('.sidenav-toggler').data('action', 'sidenav-unpin');
$('body').removeClass('g-sidenav-hidden').addClass('g-sidenav-show g-sidenav-pinned');
$('body').append('<div class="backdrop d-xl-none" data-action="sidenav-unpin" data-target='+$('#sidenav-main').data('target')+' />');
// Store the sidenav state in a cookie session
Cookies.set('sidenav-state', 'pinned');
}
function unpinSidenav() {
$('.sidenav-toggler').removeClass('active');
$('.sidenav-toggler').data('action', 'sidenav-pin');
$('body').removeClass('g-sidenav-pinned').addClass('g-sidenav-hidden');
$('body').find('.backdrop').remove();
// Store the sidenav state in a cookie session
Cookies.set('sidenav-state', 'unpinned');
}
// Set sidenav state from cookie
var $sidenavState = Cookies.get('sidenav-state') ? Cookies.get('sidenav-state') : 'pinned';
if($(window).width() > 1200) {
if($sidenavState == 'pinned') {
pinSidenav()
}
if(Cookies.get('sidenav-state') == 'unpinned') {
unpinSidenav()
}
$(window).resize(function() {
if( $('body').hasClass('g-sidenav-show') && !$('body').hasClass('g-sidenav-pinned')) {
$('body').removeClass('g-sidenav-show').addClass('g-sidenav-hidden');
}
})
}
if($(window).width() < 1200){
$('body').removeClass('g-sidenav-hide').addClass('g-sidenav-hidden');
$('body').removeClass('g-sidenav-show');
$(window).resize(function() {
if( $('body').hasClass('g-sidenav-show') && !$('body').hasClass('g-sidenav-pinned')) {
$('body').removeClass('g-sidenav-show').addClass('g-sidenav-hidden');
}
})
}
$("body").on("click", "[data-action]", function(e) {
e.preventDefault();
var $this = $(this);
var action = $this.data('action');
var target = $this.data('target');
// Manage actions
switch (action) {
case 'search-show':
target = $this.data('target');
$('body').removeClass('g-navbar-search-show').addClass('g-navbar-search-showing');
setTimeout(function() {
$('body').removeClass('g-navbar-search-showing').addClass('g-navbar-search-show');
}, 150);
setTimeout(function() {
$('body').addClass('g-navbar-search-shown');
}, 300)
break;
case 'search-close':
target = $this.data('target');
$('body').removeClass('g-navbar-search-shown');
setTimeout(function() {
$('body').removeClass('g-navbar-search-show').addClass('g-navbar-search-hiding');
}, 150);
setTimeout(function() {
$('body').removeClass('g-navbar-search-hiding').addClass('g-navbar-search-hidden');
}, 300);
setTimeout(function() {
$('body').removeClass('g-navbar-search-hidden');
}, 500);
break;
}
})
// Add sidenav modifier classes on mouse events
$('.sidenav').on('mouseenter', function() {
if(! $('body').hasClass('g-sidenav-pinned')) {
$('body').removeClass('g-sidenav-hide').removeClass('g-sidenav-hidden').addClass('g-sidenav-show');
}
})
$('.sidenav').on('mouseleave', function() {
if(! $('body').hasClass('g-sidenav-pinned')) {
$('body').removeClass('g-sidenav-show').addClass('g-sidenav-hide');
setTimeout(function() {
$('body').removeClass('g-sidenav-hide').addClass('g-sidenav-hidden');
}, 300);
}
})
// Make the body full screen size if it has not enough content inside
$(window).on('load resize', function() {
if($('body').height() < 800) {
$('body').css('min-height', '100vh');
$('#footer-main').addClass('footer-auto-bottom')
}
})
})();
Working JS Fiddle: https://jsfiddle.net/Vaulient/kthw39gs/6/

jQuery Event Duplicating function

The issue I'm having is every time you resize the browser a function is called, that function will make a side panel into an accordion if the screen width is a certain number or below or on a larger screen it's just displaying like an open side panel with no interaction.
In the resize event I call the sidepanel function. Unfortunately every time I resize the browser my side panel function is duplicated. I've been seeing stuff on unbinding but nothing that seems to make sense for how I'm calling the side panel function.
Is there a way in the resize.js to unbind the sidepanel function and rebind to the window so it's only called once every time the window is resized?
Resize.js
$(document).ready(function() {
var resizeTimer;
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
sidePanelAccordion();
}, 250);
});
});
Side-panel.js
function sidePanelAccordion() {
var panelAccordion = $('.side-panel-accordion');
var panelHeader = $('.side-panel-header');
var panelBody = $('.side-panel-body');
var panelHeaderActive = $('.mobile-header-active');
if (userScreen.type === 'mobile') {
panelAccordion.find(panelBody).hide();
panelAccordion.find(panelHeader).addClass('mobile-header-active');
} else if (userScreen.type === 'desktop') {
panelAccordion.find(panelBody).show().removeClass('open');
panelHeader.removeClass('mobile-header-active');
}
panelHeaderActive.on('click', function(e) {
console.log('clicked');
if (panelBody.hasClass('open')) {
panelBody.removeClass('open').stop(true, true).slideUp().clearQueue();
//console.log('panel had class open');
e.stopPropagation();
return false;
} else {
panelBody.addClass('open').stop(true, true).slideDown().clearQueue();
//console.log('panel now has class open');
e.stopPropagation();
return false;
}
});
}
Try this code:
panelHeaderActive.unbind('click').on('click', function(e){
console.log('clicked');
if (panelBody.hasClass('open')) {
panelBody.removeClass('open').stop(true,true).slideUp().clearQueue();
//console.log('panel had class open');
e.stopPropagation();
return false;
} else {
panelBody.addClass('open').stop(true,true).slideDown().clearQueue();
//console.log('panel now has class open');
e.stopPropagation();
return false;
}
});

Call a function using $('.class').each(functionName);

I have a codepen here -
http://codepen.io/ashconnolly/pen/EjMbQp
function homepanelHeights() {
$('.img_panel').each(function() {
if (currentWidth < 700) {
var panelcopyHeight = $(this).find('.panel_copy_inner').outerHeight();
console.log(panelcopyHeight);
$(this).css('height', panelcopyHeight);
} else {
// remove inline style
$(this).css("height", "");
}
});
}
$(document).ready(function() {
$('.img_panel').each(homepanelHeights);
});
$(window).resize(function() {
$('.img_panel').each(homepanelHeights);
});
I want to apply a function to each element with .img_panel.
Do you know why the each function call is not working?
I assume its because of the arguments I'm passing, but can not work it out.
it works if I simply repeat the function in the doc.ready and window.resize, but that is a bit dirty..
Hope you can help!
You just need to call homepanelHeights(); Because when you using $('.img_panel').each(...) in homepanelHeights, you're already iterating through it, $('.img_panel').each(homepanelHeights);, combine with the logic inside the function, can be considered as:
// This is the outer
$('.img_panel').each(function() {
// This is inside your homepanelHeights
$('.img_panel').each(function() {
// Do something.
});
});
So you can see that that the logic n*n times.
currentWidth is undefined in your codepen. Added a fake to show.
function homepanelHeights(){
$('.img_panel').each(function (){
// VVVV Make the `currentWidth` get value here, it needs the current width
// when window content is fully loaded, or resized.
var currentWidth = $(window).width();
if (currentWidth < 700){
var panelcopyHeight = $(this).find('.panel_copy_inner').outerHeight();
console.log(panelcopyHeight);
$(this).css('height', panelcopyHeight);
} else {
// remove inline style
$(this).css("height", "");
}
});
}
// As A. Wolff said :
// $(window).on('load resize', homepanelHeights); Can simplify the code.
$(document).ready(function() {
homepanelHeights();
});
$(window).resize(function() {
homepanelHeights();
});
.img_panel {background:salmon; width:200px; height:300px; margin-bottom:10px; display:table;
.panel_copy_inner {height:100%; display: table-cell; vertical-align:middle; text-align: center;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="img_panel">
<div class="panel_copy_inner">Test</div>
</div>
<div class="img_panel">
<div class="panel_copy_inner">Test</div>
</div>
<div class="img_panel">
<div class="panel_copy_inner">Test</div>
</div>
If you want to use the function homepanelHeights as $('.img_panel').each(homepanelHeights);
You can rewrite the logic to:
var currentWidth;
// You need to either define a `currentWidth` here by something.
function homepanelHeights(){
if (currentWidth < 700){
var panelcopyHeight = $(this).find('.panel_copy_inner').outerHeight();
console.log(panelcopyHeight);
$(this).css('height', panelcopyHeight);
} else {
// remove inline style
$(this).css("height", "");
}
}
// As A. Wolff said :
$(window).on('load resize', function() {
// Update the width here. So you don't need to get currentWidth
// each time you operate on an element.
currentWidth = $(window).width();
$('.img_panel').each(homepanelHeights);
});
Demo is on jsfiddle.
Here i have modified the code to achieve the functionality for each element.
Please see the code below.
homepanelHeights=function(key, val) {
var currentWidth = $(window).width();
console.log(currentWidth);
if (currentWidth < 700) {
var panelcopyHeight = $(this).find('.panel_copy_inner').outerHeight();
//console.log(panelcopyHeight);
$(this).css('height', panelcopyHeight);
} else {
// remove inline style
$(this).css("height", "");
}
}
/**/
$(document).ready(function() {
$('.img_panel').each(homepanelHeights);
});
$(window).resize(function() {
$('.img_panel').each(homepanelHeights);
});
function homepanelHeights(){
//This will iterate through all element having img_panel class
$('.img_panel').each(function(){
//get current div's height
var currentWidth = //assign some value here, it is undefined in your current code;
// your logic implemetation
if (currentWidth < 700)
{
var panelcopyHeight = $(this).find('.panel_copy_inner').outerHeight();
console.log(panelcopyHeight);
$(this).css('height', panelcopyHeight);
}
else {
$(this).css("height", "");
}
})
}
// on window load && resize
$(window).on('load resize',function() {
homepanelHeights();
});
//Or instead of window on load you can also use document's ready event
$(document).ready(function() {
homepanelHeights();
});
document.ready runs when the DOM is ready, e.g. all elements are there to be found/used, but not necessarily all the content.
window.onload fires later (or at the same time in the worst/failing cases) when images and such are loaded. So, if you're using image dimensions for example, you often want to use this instead

How to stop window.scroll() after specific event?

I want to make the sticky-nav to act similar(scroll is off when the menu is expanded) to this website's nav(http://amandagerhardsen.com/#cloudbusting/4) when expanded.
How do I do it?
var Boxlayout = (function () {
var $el = $('#sticky-nav'),
$sections = $el.children('section'),
// work panels
$workPanelsContainer = $('#bl-panel-work-items'),
// close work panel trigger
$closeWorkItem = $workPanelsContainer.find('nav > span.hidemenu'),
transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
// transition end event name
transEndEventName = transEndEventNames[Modernizr.prefixed('transition')],
// support css transitions
supportTransitions = Modernizr.csstransitions;
function init() {
initEvents();
}
function initEvents() {
$sections.each(function () {
var $section = $(this);
// expand the clicked section and scale down the others
$section.on('click', function () {
if (!$section.data('open')) {
$section.data('open', true).addClass('bl-expand bl-expand-top');
$el.addClass('bl-expand-item');
}
}).find('span.hidemenu').on('click', function () {
// close the expanded section and scale up the others
$section.data('open', false).removeClass('bl-expand').on(transEndEventName, function (event) {
if (!$(event.target).is('section')) return false;
$(this).off(transEndEventName).removeClass('bl-expand-top');
});
if (!supportTransitions) {
$section.removeClass('bl-expand-top');
}
$el.removeClass('bl-expand-item');
return false;
});
});
// clicking on a work item: the current section scales down and the respective work panel slides up
$workItems.on('click', function (event) {
// scale down main section
$sectionWork.addClass('bl-scale-down');
// show panel for this work item
$workPanelsContainer.addClass('bl-panel-items-show');
var $panel = $workPanelsContainer.find("[data-panel='" + $(this).data('panel') + "']");
currentWorkPanel = $panel.index();
$panel.addClass('bl-show-work');
return false;
});
// navigating the work items: current work panel scales down and the next work panel slides up
$nextWorkItem.on('click', function (event) {
if (isAnimating) {
return false;
}
isAnimating = true;
var $currentPanel = $workPanels.eq(currentWorkPanel);
currentWorkPanel = currentWorkPanel < totalWorkPanels - 1 ? currentWorkPanel + 1 : 0;
var $nextPanel = $workPanels.eq(currentWorkPanel);
$currentPanel.removeClass('bl-show-work').addClass('bl-hide-current-work').on(transEndEventName, function (event) {
if (!$(event.target).is('div')) return false;
$(this).off(transEndEventName).removeClass('bl-hide-current-work');
isAnimating = false;
});
if (!supportTransitions) {
$currentPanel.removeClass('bl-hide-current-work');
isAnimating = false;
}
$nextPanel.addClass('bl-show-work');
return false;
});
// clicking the work panels close button: the current work panel slides down and the section scales up again
$closeWorkItem.on('click', function (event) {
// scale up main section
$sectionWork.removeClass('bl-scale-down');
$workPanelsContainer.removeClass('bl-panel-items-show');
$workPanels.eq(currentWorkPanel).removeClass('bl-show-work');
return false;
});
}
return {
init: init
};
})();
Here is a fiddle: http://jsfiddle.net/77P2e/
Be careful to unlock scrolling again when done, or this could be very annoying for the user!
Setup code
var $window = $(window), previousScrollTop = 0, scrollLock = false;
$window.scroll(function(event) {
if(scrollLock) {
$window.scrollTop(previousScrollTop);
}
previousScrollTop = $window.scrollTop();
});
To lock scroll position:
scrollLock = true;
And to unlock again...
scrollLock = false;
As an example use, you could lock the window scroll position when the mouse enters the navigation area, and unlock it again when the mouse leaves:
$("nav")
.mouseenter(function(){ scrollLock = true; })
.mouseleave(function(){ scrollLock = false; });
In my opinion the accepted answer is not what should be achieved, as the window.scroll() function will be still running (endlessly), even if the 'event' has occured.
The window.scroll() function is an event handler. So use on() to bind the event and off() to unbind it (after the 'event' has occured).
$(window).on('scroll', function() { // bind event handler
var offset = $(window).scrollTop();
console.log("page Y-Offset: ", offset); // just to see it working
if(offset >= 100) $(window).off('scroll'); // unbind the event handler when the condition is met
});
The Javascript solution is a little janky for me, on mobile. It's like it scrolls a little bit and then snaps back into place.
However, I figured out a way to do it much more cleanly, without any jank, just by changing CSS's overflow property on the part you don't want to scroll. Here's the code in d3 but the concept should be pretty clear:
var body = d3.select('body');
var preventScroll = function () {
body.style('overflow', 'hidden');
},
allowScroll = function () {
body.style('overflow', 'scroll');
};
d3.select('#sticky-nav')
.on('touchmove', preventScroll)
.on('touchstart', preventScroll)
.on('touchend', allowScroll)
.on('touchcancel', allowScroll);
As I was using jquery animation,
if ($(window).scrollTop() >= $('.btn').offset().top + $('.btn').outerHeight() - window.innerHeight)
{
$(".tab").stop();
}
I did this and it worked.
.btn is the button. That .tab div would stop if it scrolls to that position.
If you're using jquery animation you can try using the stop() function on the animated object.

Repeating code block problem

I have the following code in a jQuery JavaScript document running on a page (THIS IS CURRENT):
$(window).resize(function(){
detectscreen();
});
function windowWidth() {
if(!window.innerWidth) {
// user is being a git, using ie
return document.documentElement.clientWidth;
} else {
return window.innerWidth;
}}
gearsExists = false;
function detectscreen() {
shouldExist = windowWidth() >= 1300;
if (shouldExist != gearsExists) {
if (shouldExist) {
$('body').append('<div id="gearsfloat"></div>');
$('#clickGoTop').fadeTo(0,0);
$('#clickGoTop').hover(function() {
$(this).stop().fadeTo(500,1);
}, function() {
$(this).stop().fadeTo(500,0);
});
} else {
$('#gearsfloat').remove();
$('#clickGoTop').remove();
}
gearsExists = shouldExist;
}
}
This code is from my previous question, branched here simply because I think it is related.
The problem here is that the beginning is fine: it is displayed. However, if the screen is resized to less than 1300, it disappears; still good.
Now I make the window again larger than 1300. Suddenly the gear element is doubled. Another screen squish and largen and BAM, there's three now. Do this several times and it quickly adds up.
How can I stop this?
If you hook any code in resize event, make sure that your code doesn't resize the window again. Otherwise, resize event will fire again and your code will go in infinite loop.
Also, in your code, you are not using the global gearsExists variable. Remove the 'var' at the bottom of the method to use the global variable.
function detectscreen() {
// Your original code
//var gearsExists = shouldExist; //This code will create new local variable.
gearsExists = shouldExist;
}
}
EDIT: Here's what I would do:
//We will add only one variable to the global scope.
var screenManager = function()
{
var pub = {};
var inResizeHandler = false;
pub.getWindowWidth = function()
{
return window.innerWidth || document.documentElement.clientWidth;
};
pub.manage = function()
{
//if we are already in the resize handler, don't do anything.
if(inResizeHandler)
return;
inResizeHandler = true;
if(pub.getWindowWidth() < 1300)
{
$('#gearsfloat').remove();
//You don't have to remove clickGoTop because it is part of gearsfloat.
inResizeHandler = false;
return;
}
if($('#gearsfloat').length > 0)
{
inResizeHandler = false;
return false;
}
$('body').append('<div id="gearsfloat"></div>');
$('#clickGoTop').fadeTo(0,0);
$('#clickGoTop').hover(
function() {$(this).stop().fadeTo(500,1);},
function() {$(this).stop().fadeTo(500,0);
});
inResizeHandler = false;
};
pub.init = function()
{
$(window).resize(pub.manage);
};
return pub;
}();
$(document).ready( function() { screenManager.init(); } );
EDIT:
Final working version:
http://jsbin.com/ufipu
Code:
http://jsbin.com/ufipu/edit
Haha! After a while, I decided to ignore everything said by everyone else for a while (sorry) and try to see if I could figure it out myself, and I did!
Thanks to SolutionYogi for all the help, but the code he gave me was out of my expertise; it was impossible to debug. My solution is not as pretty as his (if you can help optimize, please do), but it works:
function WinWidth() {
// check width of content
if(!window.innerWidth) {
// you git, how dare you use ie
return document.documentElement.clientWidth;
} else {
return window.innerWidth;
}
};
function gearsAction() {
if(WinWidth() >= 1300) {
$('body').append(
'<div id="gearsfloat"></div>');
$('#clickGoTop').fadeTo(0,0);
$('#clickGoTop').hover(
function() {$(this).stop().fadeTo(500,1);},
function() {$(this).stop().fadeTo(500,0);});
};
};
$(document).ready(function() {
gearsAction();
});
$(window).resize(function() {
$('#gearsfloat').remove();
gearsAction();
});

Categories

Resources