I need to account for navbar size after the page has loaded if a hash id has been passed in url e.g. example.com#id-of-some-element
I am trying to use the following:
$(document).ready(function(){
if(window.location.hash){
$(window).scrollTop($(window).scrollTop() - 80);
}
});
However $(window).scrollTop() in this case always returns 0.
This leads me to think that .ready fires before the navigation to the hash id has been done.
I believe your theory is correct. Below are 3 examples, one using $(document).ready(), one using $(window).load(), and one with logic to make the adjustment after the first scroll (but not subsequent scrolls).
All 3 show expected $(window).scrollTop() values, but $(document).ready() always appears in the hash location rather than the expected shifted location. $(window).load() appears with the expected 80px adjustment some of the time, but it is not consistent. The third option uses logic that should always work, though it's admittedly a bit clunky. There may be a better solution, but I hope this helps!
Try expanding each snippet and clicking "Run code snippet" repeatedly to see results over several test runs.
Never works: Using $(document).ready():
if (!window.location.hash) {
window.location = window.location + "#id-of-some-element";
}
$(document).ready(function() {
console.log($(window).scrollTop());
if (window.location.hash) {
$(window).scrollTop($(window).scrollTop() - 80);
console.log($(window).scrollTop());
}
});
.tall-div {
height: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tall-div">DIV 1</div>
<div id="id-of-some-element">Some Element</div>
<div class="tall-div">DIV 2</div>
Sometimes works: Using $(window).load():
if (!window.location.hash) {
window.location = window.location + "#id-of-some-element";
}
$(window).load(function() {
console.log($(window).scrollTop());
if (window.location.hash) {
$(window).scrollTop($(window).scrollTop() - 80);
console.log($(window).scrollTop());
}
});
.tall-div {
height: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tall-div">DIV 1</div>
<div id="id-of-some-element">Some Element</div>
<div class="tall-div">DIV 2</div>
Always works: Using logic to detect first scroll:
if (!window.location.hash) {
window.location = window.location + "#id-of-some-element";
}
var loading = true;
$(window).scroll(function(event) {
if (loading) {
console.log($(window).scrollTop());
if (window.location.hash) {
$(window).scrollTop($(window).scrollTop() - 80);
console.log($(window).scrollTop());
}
loading = false;
}
});
.tall-div {
height: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tall-div">DIV 1</div>
<div id="id-of-some-element">Some Element</div>
<div class="tall-div">DIV 2</div>
Related
I have a form that has several "pages" with each "page" being a container holding some content.
I would like to have previous and next buttons following these rules:
Clicking the next button should progress forward through the form's pages until the last page and stop
Clicking the previous button should progress backwards through the form until the first page and stop.
Here is the example of similar functionality except it does't follow the rules above because hitting next on the last page cycles back to the first and vice versa.
Here is what I have tried so far:
JS
$('.box button').click(function() {
$('.box').each( function() {
if ($(this).offset().left < 0) {
$(this).css("left", "150%");
}
});
var t=$(this);
t.parent().animate({
left: '-50%'
}, 500);
if (t.parent().next().size() > 0) {
t.parent().next().animate({
left: '50%'
}, 500);
} else {
t.parent().prevAll().last().animate({
left: '50%'
}, 500);
}
});
The below is one method that will achieve this (note that this could be simplified a good bit but doing so here would make it more difficult to understand for new programers):
$('.previous').click(function () {
var cur = $('.form-panel').index($('.form-panel.active'));
if (cur!=0) {
$('.form-panel').removeClass('active');
$('.form-panel').eq(cur-1).addClass('active');
}
});
$('.next').click(function () {
var cur = $('.form-panel').index($('.form-panel.active'));
if (cur!=$('.form-panel').length-1) {
$('.form-panel').removeClass('active');
$('.form-panel').eq(cur+1).addClass('active');
}
});
.form-panel:not(.active) {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-panel active">Panel one content here</div>
<div class="form-panel">Panel two content here</div>
<div class="form-panel">Panel three content here</div>
<div class="form-panel">Panel four content here</div>
<div class="form-panel">Panel five content here</div>
<div class="form-panel">Panel six content here</div>
<br>
<button class="previous">Previous</button>
<button class="next">Next</button>
If you require animations, this method can easily be modified to include them.
So right now I have this code:
var s = 0;
$('.inner').click(function () {
$(this).addClass("selected");
$(this).removeClass("inner");
s++;
$('#sslots').replaceWith(s);
};
But for some reason, the javascript wont update, it will start out as blank (not zero) and then change to 1 once I click one of the div's with "inner" as the class but then won't do anything after that..
The problem is after your first click the element sslots does not exists because you are replacing it with the number, instead you have to change the content of sslots - you can use .text() for that
var s = 0;
$('.inner').one('click', function() {
$(this).addClass("selected");
$(this).removeClass("inner");
s++;
$('#sslots').text(s);
});
.inner {
color: green;
}
.selected {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="sslots">0</div>
<div class="inner">inner</div>
<div class="inner">inner</div>
<div class="inner">inner</div>
<div class="inner">inner</div>
<div class="inner">inner</div>
Also from the code it looks like you want to execute the click once per inner element(ie if you click multiple times in an element only first one should count), in that cause use .one() to register a handler which will be executed only once
How can I make this scroll left or right using navigation button?
<div class="slider-wrap">
<div class="slide-wrap">
<div class="slider-slide-wrap"></div>
<div class="slider-slide-wrap"></div>
<div class="slider-slide-wrap"></div>
</div>
</div>
<div id="slider-left" class="slider-nav"></div>
<div id="slider-right" class="slider-nav"></div>
JS
$("#slider-left").click(function(){
alert("< clicked.");
});
$("#slider-right").click(function(e){
alert("> clicked.");
$('.slide-wrap').scrollLeft(5000);
});
Fiddle
You are selecting the wrong <div>. Note the selector: $('.slider-wrap') (not .slide-wrap).
$("#slider-left").click(function () {
$('.slider-wrap').animate({
scrollLeft: 0
}, 200);
});
I have used .animate because you get visual feedback about what's happening (so I think using animate is better for UX). This would work equally well with .scrollLeft() though:
$("#slider-left").click(function () {
$('.slider-wrap').scrollLeft(0);
});
See it working in a fiddle
I want to create a sticky div as smooth as in this example: http://www.nytimes.com/interactive/2010/11/13/weekinreview/deficits-graphic.html?src=tp&_r=0
Right now, my example isnt smooth at all, but really jumpy. I have this JS-code:
$(window).scroll(function () {
var scroll_top = $(this).scrollTop();
if (scroll_top > 66) {//height of header
$('.wrapper').addClass('sticky');
} else {
$('.wrapper').removeClass('sticky');
}
});
And the HTML:
<div class="wrapper">
<h4>Ausgaben in Millionen Franken</h4>
<div class="background">
<div id="kunstmuseum"></div><div id="historisch"></div><div id="naturhist"></div><div id="kulturen"></div><div id="antik"></div><div id="beyeler"></div><div id="weitereMuseen"></div><div id="theaterBasel"></div><div id="kaserne"></div><div id="weitereTheater"></div><div id="sinfonie"></div><div id="jazz"></div><div id="rock"></div><div id="literatur"></div><div id="erbe"></div><div id="wettbewerb"></div><div id="weiteres"></div><div id="zoo"></div>
</div>
<div id="eins">0</div>
<div id="zwei">30</div>
<div id="drei">60</div>
<div id="vier">90</div>
<div id="fuenf">120</div>
<div id="eingespart"><h4>Total eingespart: <div id="totalSum">0 CHF</div></h4></div>
</div>
Here is the jsfiddle: http://jsfiddle.net/w640ftLf/3/
It's not really how I would do it, but your function works fine.
The easiest way to fix your problem is to add padding-top: 66px; (66 being the header height) to the body element at the same time you add the class 'sticky'.
Let me know if this works for you.
It looks like you're attaching the sticky class to the wrong element. Try this, instead:
$(window).scroll(function () {
var scroll_top = $(document).scrollTop();
if (scroll_top > 66) {//height of header
$('.background').addClass('sticky');
} else {
$('.background').removeClass('sticky');
}
});
Also, for education, you can take a look at how your example is doing it.
I have this div scrolling script:
$(document).ready(function () {
$('.tab-box').each(function () {
var top = 0;
var $tabbox = $(this);
var height = $tabbox.height();
$(this).find('.tab').each(function () {
var shift = top;
$(this).click(function () {
$tabbox.find('.items').animate({
marginTop: shift + 'px'
});
$tabbox.find('.tab').removeClass('active');
$(this).addClass('active');
});
top -= height;
});
$(this).find('.tab:eq(0)').addClass('active');
});
});
If I understand it correctly it gets every divs working only within the div "tab-box".
http://jsfiddle.net/9SfEH/5/
What I want to change is that I separate the "tabs" from the main tab-box div, but make them still controll the "items".
http://jsfiddle.net/w65Dn/1/
I was trying for a simple solution buuut couldn't come up with one by myself.
Thanks everyone in advance :)
The problem was that in the original code, it was looking for the tab clickables using $(this).find(".tab"), but the .tabs were no longer inside of the .tab-box. So, if you just search globally, with $(".tab"), it works.
Note that you can no longer have more than one tab box, because it is searching globally for the .tabs. You could use something like javaCity's solution (i.e. wrapping everything in another div) to fix this.
You were looking for .tabs inside the tab-box which does not exist. So how about creating a div outside of .tabs which also encloses tab-box?
http://jsfiddle.net/3D8we/
HTML:
<div class="enclosingDiv">
<div class="tabs">
<div class="tab">1</div>
<div class="tab">2</div>
<div class="tab">3</div>
</div>
<div class="tab-box">
<div class="items">
<div class="item" style="background: #cbe86b;"></div>
<div class="item" style="background: #f2e9e1;"></div>
<div class="item" style="background: #1c140d;"> </div>
</div>
</div>
</div>
JS:
$(document).ready(function () {
$('.tab-box').each(function () {
var top = 0;
var $tabbox = $(this);
var height = $tabbox.height();
$('.enclosingDiv').find('.tab').each(function () {
var shift = top;
$(this).click(function () {
$tabbox.find('.items').animate({
marginTop: shift + 'px'
});
$tabbox.find('.tab').removeClass('active');
$(this).addClass('active');
});
top -= height;
});
$(this).find('.tab:eq(0)').addClass('active');
});
});
On line 7, change the selector from this to .tabs
$(this).find('.tab') becomes $(.tabs).find('.tab')
as seen here: jsfiddle example