Use function everywhere without writing it more than once - javascript

Trying to get my code cleaner I don't want to write the same code many times but don't know how to accomplish it. You can see in the code below is the if/else written twice but doing the same. How can I return data and call that function again with writing it only once?
Help and advices are much appreciated.
Code is like this:
(function($){
var scroll = $(this).scrollTop();
var header = $('header');
var headerSmall = header.children('.small');
var headerBigWrap = header.children('.big');
var headerBigWrapHeight = headerBigWrap.height();
var showNav = function() {
header.css('position','fixed');
headerBigWrap.css('display','none');
headerSmall.css('display','block');
}
var hideNav = function() {
header.css('position','static');
headerSmall.css('display','none');
headerBigWrap.css('display','block');
}
// don't want to write this more than once
// but need to call here on document ready
if( scroll >= headerBigWrapHeight ) {
showNav();
} else {
hideNav();
}
$(window).scroll(function(event){
scroll = $(this).scrollTop();
// here I need it again
// scroll is changing on scroll
// but "function" does exactly the same like above
if( scroll >= headerBigWrapHeight ) {
showNav();
} else {
hideNav();
}
});
})(jQuery);
if you need html and css working example: fiddle http://jsfiddle.net/cejs3jhs/ and rest of code:
<header>
<div class="big">
<h1>Page Title</h1>
</div>
<div class="small">
<span class="icon nav-icon">Nav Icon</span>
</div>
</header>
<div class="page"></div>
<style type="text/css">
header {
width:100%;
background-color:red;
opacity:0.5;
}
header.toggle-nav {
height:100%;
}
header.toggle-nav ul {
display:block;
}
header > div {
position:relative;
width:976px;
margin:0 auto;
}
header > div.big {
padding:30px 0;
}
.page {
height:5000px;
background-color:orange;
opacity:0.5;
}
</style>

So just make separate function for that:
function showHideNav(scroll, headerBigWrapHeight, element) {
var scroll = element.scrollTop(),
header = $('header'),
headerSmall = header.children('.small'),
headerBigWrap = header.children('.big')
headerBigWrapHeight = headerBigWrap.height();
if( scroll >= headerBigWrapHeight ) {
header.css('position','fixed');
} else {
header.css('position','static');
}
headerBigWrap.toggle();
headerSmall.toggle();
}
(function($){
showHideNav(scroll);
$(window).scroll(function(event){
scroll = $(this).scrollTop();
showHideNav(scroll);
});
})(jQuery);

The answer to your question is simply what Justinas said, make another function. But you can improve a bit with some more aggressive editing, which is what I've done.
(function ($) {
var header = $('header');
var headerSmall = header.children('.small');
var headerBigWrap = header.children('.big');
var headerBigWrapHeight = headerBigWrap.height();
function setNavStyle() {
var scroll = $(this).scrollTop();
if( scroll >= headerBigWrapHeight ) {
header.css('position', 'fixed');
headerSmall.css('display', 'block');
headerBigWrap.css('display', 'none');
} else {
header.css('position', 'static');
headerSmall.css('display', 'none');
headerBigWrap.css('display', 'block');
}
}
$(window).scroll(setNavStyle);
setNavStyle();
})(jQuery);
That's one way, but it would be better (more maintainable, simpler, faster) to do the bulk of
the work with CSS, like so:
CSS:
header {
position: static;
}
header>.small {
display: none;
}
header>.big {
display: block;
}
.stickyNav header {
position: fixed;
}
.stickyNav header>.small {
display: block;
}
.stickyNav header>.big {
display: none;
}
JavaScript:
(function ($) {
var bigNavHeight = $('header>.big').height();
function setNavStyle() {
var bigIsOffscreen = $(this).scrollTop() >= bigNavHeight;
$(document.body).toggleClass('stickyNav', bigIsOffscreen);
}
$(window).scroll(setNavStyle);
setNavStyle();
})(jQuery);

You can define a new function just as you did with the showNav & hideNav functions
(function($){
var scroll = $(this).scrollTop();
var header = $('header');
var headerSmall = header.children('.small');
var headerBigWrap = header.children('.big');
var headerBigWrapHeight = headerBigWrap.height();
var showNav = function() {
header.css('position','fixed');
headerBigWrap.css('display','none');
headerSmall.css('display','block');
}
var hideNav = function() {
header.css('position','static');
headerSmall.css('display','none');
headerBigWrap.css('display','block');
}
var checkScroll = function (scroll,headerBigWrapHeight){
if( scroll >= headerBigWrapHeight ) {
showNav();
} else {
hideNav();
}
checkScroll(scroll,headerBigWrapHeight);
$(window).scroll(function(event){
scroll = $(this).scrollTop();
checkScroll(scroll,headerBigWrapHeight);
});
})(jQuery);

Please find below updated JS code:
(function($){
var scroll = $(this).scrollTop();
var header = $('header');
var headerSmall = header.children('.small');
var headerBigWrap = header.children('.big');
var headerBigWrapHeight = headerBigWrap.height();
var showNav = function() {
header.css('position','fixed');
headerBigWrap.css('display','none');
headerSmall.css('display','block');
}
var hideNav = function() {
header.css('position','static');
headerSmall.css('display','none');
headerBigWrap.css('display','block');
}
var callFun = function(scroll) {
if( scroll >= headerBigWrapHeight ) {
showNav();
} else {
hideNav();
}
}
callFun(scroll);
$(window).scroll(function(event){
scroll = $(this).scrollTop();
callFun(scroll);
});
})(jQuery);

Do it exactly like you have done with functions showNav and hideNav: define a function with if/else inside somewhere and you can call it by name wherever needed. There are also some variables which can be omitted then, so I show all code here:
(function($){
// var scroll is moved into function scrollFunc
var header = $('header');
var headerSmall = header.children('.small');
var headerBigWrap = header.children('.big');
// var headerBigWrap is moved into function scrollFunc
var showNav = function() {
/* your code */
}
var hideNav = function() {
/* your code */
}
var scrollFunc = function () {
if($(this).scroll() >= headerBigWrap.height() ) {
showNav();
} else {
hideNav();
}
}
$(window).scroll(function(event){
scrollFunc();
});
scrollFunc(); // call it first time to initialize
});

Related

Why Javascript sticky header doesn't work?

I made a website with a sticky header and it worked well. Some other people worked with it too and they made some changes, but now the stickiness of the header doesn't work. I tried to put back the old code but It didn't help.
var modalBtn = document.querySelector(".cta-add"),
modalBg = document.querySelector(".modal-bg"),
modalClose = document.querySelector(".modal-close");
modalBtn.addEventListener("click", function() {
modalBg.classList.add("bg-active");
}),
modalClose.addEventListener("click", function() {
modalBg.classList.remove("bg-active");
}),
$("#booknow")
.on("click", function() {
$.getScript("https://fareharbor.com/embeds/api/v1/?autolightframe=yes");
})
.done(function() {
window.location.href =
"https://fareharbor.com/embeds/book/.../items/148437/?full-items=yes&flow=no";
});
$("#contact").on("click", function() {
$.getScript("headers.php?file=recaptcha.js");
}),
(window.onscroll = myFunction);
var header = document.getElementById("myHeader"),
sticky = header.offsetTop;
function myFunction() {
header.classList.toggle('sticky', window.pageYOffset > sticky);
}
function openTab(e, t) {
var n, c, a;
for (
c = document.getElementsByClassName("tabcontent"), n = 0; n < c.length; n++
)
c[n].style.display = "none";
for (
a = document.getElementsByClassName("tablinks"), n = 0; n < a.length; n++
)
a[n].className = a[n].className.replace(" active", "");
(document.getElementById(t).style.display = "block"),
(e.currentTarget.className += " active");
}
const hamburger = document.querySelector(".hamburger"),
navLinks = document.querySelector(".nav-links"),
links = document.querySelectorAll(".nav-links li");
var mylogo = document.getElementById("myLogo");
hamburger.addEventListener("click", () => {
navLinks.classList.toggle("open"),
links.forEach((e) => {
e.classList.toggle("fade");
});
}),
$(document).ready(function() {
$("#hamburgerID").on("click", function() {});
}),
$(".nav-links li a").on("click", function() {
$("#hamburgerID").click();
});
.sticky {
position: fixed;
top: 10;
height: 20vh;
width: 100%;
align-items: center;
background: #fff;
}
I implemented this in my old code, and it is working. My question is what else can cause this problem?
I changed the modalBtn.addEventListener function to this:
modalClose.addEventListener('click',function(){
modalBg.classList.remove('bg-active');
});
It is good now, but If someone could tell me what was the problem with the old code I would be grateful.

Event on scrolling up or down

I wanna detect when the user scrolls. I saw there are some questions about this but those answers didn't help me.
Here is my code:
var up = document.getElementById('up');
var down = document.getElementById('down');
function onScroll() {
if (view.scrollTop > 0) {
console.log("up");
}
if (view.scrollTop < 0) {
console.log("down");
}
}
var view = document.getElementById('container');
view.addEventListener("wheel", onScroll);
EDIT: "scroll" instead "wheel" isn't working for me... I must have the "wheel". When I make:
if (view.scrolltop <=0) {
console.log("down");
}
that I get in my console "down" but it appears when I scrolling up too! I have my page in 100% of screen and I have no scrollbars (and I don't want to have).
EDIT2: Here is the code that solved my problem!
window.addEventListener('wheel', function (e) {
if (e.deltaY < 0) {
console.log("scrolling up");
}
if (e.deltaY > 0) {
console.log("scrolling down");
}
});
you can use the
window.onscroll
to get the scrolling event, then just use
.scrollTop
to determine your offset from the top of page or an element.
window.onscroll = function() { scrollFunction() };
scrollFunction() {
//code to check if it is scrolling up or down
}
Hopefully this was a helpful start.
I did this with the jquery method
var last = 0;
$(window).scroll(function(event){
var Pos = $(this).scrollTop();
if (Pos > last ){
// down
} else {
// up
}
last = Pos;
});
Supporting #Belmin Bedak's comment.
Use .scroll instead of .wheel:
var up = document.getElementById('up');
var down = document.getElementById('down');
function onScroll() {
if (view.scrollTop > 0) {
alert("up");
}
if (view.scrollTop <= 0) {
alert("down");
}
}
var view = document.getElementById('container');
view.addEventListener("scroll", onScroll);
div {
border: 1px solid black;
width: 200px;
height: 100px;
overflow: scroll;
}
<div id='container'>a<br>
b<br>
c<br>
d<br>
e<br>
f<br>
g<br>
h<br>
i<br>
k<br>
l<br>
</div>

Change url when manually scrolled to an id even scrolling to top?

Is it possible to change the URL in the address bar instantly when I scroll to an id? Or have a long document with multiple id and the url changes on address bar, when I hit a new id even i scroll form bottom to top.
i use Change url when manually scrolled to an anchor?
but this is not working when scroll from bottom to top.
$(function () {
var currentHash = "#";
$(document).scroll(function () {
$('.block').each(function () {
var top = window.pageYOffset;
var distance = top - $(this).offset().top;
var hash = $(this).attr('id');
// 30 is an arbitrary padding choice,
// if you want a precise check then use distance===0
if (distance < 30 && distance > -30 && currentHash != hash) {
window.location.hash = (hash);
currentHash = hash;
}
});
});
});
body {
margin: 0px;
}
div {
height: 900px;
text-align: center;
padding: 15px;
background-color: #00f;
}
div:nth-child(even) { background: #ccc; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div class="block" id="one">Block 1</div>
<div class="block" id="two">Block 2</div>
<div class="block" id="three">Block 3</div>
<div class="block" id="four">Block 4</div>
<div class="block" id="five">Block 5</div>
Thanks in advance.
After your comment, I understand what you are trying to achieve:
The following code is based on scroll up/ down.
Will store the current block and make you "jump" between blocks:
$(function () {
var blocksArr = $('.block');
var lastScrollTop = 0;
var currentBlock = 0;
$(document).scroll(function () {
var st = $(this).scrollTop();
var hash;
//make sure it is in the boundaries
if (st > lastScrollTop && currentBlock< blocksArr.length -1){
// downscroll code
hash = $(blocksArr[++currentBlock]).attr('id');
window.location.hash = (hash);
}
else
if (st < lastScrollTop && currentBlock > 0){
// scrollup code
hash = $(blocksArr[--currentBlock]).attr('id');
window.location.hash = (hash);
}
lastScrollTop = $(this).scrollTop();
});
});
"working" fiddle (hash wont change on fiddle)
added:
If you only want to see the URL changes:
$(function () {
var currentHash = "#";
var blocksArr = $('.block');
$(document).scroll(function () {
var currentTop = window.pageYOffset/1;
for (var i=0; blocksArr.length; i++){
var currentElementTop = $(blocksArr[i]).offset().top;
var hash = $(blocksArr[i]).attr('id');
if (currentElementTop < currentTop && currentTop < currentElementTop + $(blocksArr[i]).height() && currentHash!=hash){
if(history.pushState) {
history.pushState(null, null, '#'+hash);
}
else {
location.hash = '#'+hash;
}
currentHash = hash;
}
}
});
});

Sticky navbar working on jsfiddle, but not as expected on localhost

I've put together a sticky navbar that appears after 10px in a relative position, and then becomes fixed once it scrolls past offset().top.
This works as desired on the fiddle, but on localhost (with the exact same code) the navbar is fixed as soon as it appears (it ought to be relatively positioned till the offset point, as demonstrated in the fiddle).
Would appreciate any insight on why it's behaving different on the localhost?
Also, I've added jquery (<script type="text/javascript" src="//code.jquery.com/jquery-1.11.3.min.js"></script>) and there are no console errors.
Here is the javascript as i'm running it from the localhost:
<script type="text/javascript">
document.getElementById('navig').style.visibility = 'hidden';
var fixed = false;
var topTrigger = $('#navig').offset().top;
$(window).scroll(function () {
if ($(this).scrollTop() > 10) {
document.getElementById('arr_downpoint').style.visibility = 'hidden';
document.getElementById('navig').style.visibility = 'visible';
}
else {
document.getElementById('arr_downpoint').style.visibility = 'visible';
document.getElementById('navig').style.visibility = 'hidden';
}
});
$(document).scroll(function() {
if( $(this).scrollTop() >= topTrigger ) {
if( !fixed ) {
fixed = true;
$('#navig').css({'position':'fixed', 'top':'0'});
}
} else {
if( fixed ) {
fixed = false;
$('#navig').css({'position':'relative'});
}
}
});
</script>
Try wrapping everything inside your <script> tag into $(document).ready() function:
$(function () {
document.getElementById('navig').style.visibility = 'hidden';
var fixed = false;
var topTrigger = $('#navig').offset().top;
$(window).scroll(function () {
if ($(this).scrollTop() > 10) {
document.getElementById('arr_downpoint').style.visibility = 'hidden';
document.getElementById('navig').style.visibility = 'visible';
}
else {
document.getElementById('arr_downpoint').style.visibility = 'visible';
document.getElementById('navig').style.visibility = 'hidden';
}
});
$(document).scroll(function() {
if( $(this).scrollTop() >= topTrigger ) {
if( !fixed ) {
fixed = true;
$('#navig').css({'position':'fixed', 'top':'0'});
}
} else {
if( fixed ) {
fixed = false;
$('#navig').css({'position':'relative'});
}
}
});
});

Why isn't it possible to change max-height with % in javascript?

I'm trying to build a responsive menu, with a hamburger icon. I want the menu list to slide in and out, no jquery - pure javascript only.
HTML :
<div id="animation">
</div>
<button id="toggle">Toggle</button>
CSS :
div {
width: 300px;
height: 300px;
background-color: blue;
}
Javascript :
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback){
var inter = -1, start = 100, end = 0;
if(type==true){
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function(){
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if(start == end){
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function(){
animate(hidden, function(){
hidden = (hidden == false) ? true : false;
});
}
div.style.maxHeight = "50%";
The problem is that proportional height in an element needs a fixed height on the parent, and you didn't provided any parent with a fixed height because for the maxHeight property too the % Defines the maximum height in % of the parent element.
You have to put your div in a parent container with a fixed height, this is your working code:
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback) {
var inter = -1,
start = 100,
end = 0;
if (type) {
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function() {
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function() {
animate(hidden, function() {
hidden = !hidden ;
});
}
div.style.maxHeight = "50%";
#animation {
width: 300px;
height: 300px;
background-color: blue;
}
#parent {
width: 500px;
height: 500px;
}
<div id="parent">
<div id="animation">
</div>
<button id="toggle">Toggle</button>
</div>
Note:
As stated in comments there are some statements in your JavaScript code that need to be adjusted:
if(type==true) can be written as if(type).
hidden = (hidden == false) ? true : false; can be shortened to hidden = !hidden
There seems to be a few errors with your code. I have fixed the js and added comments to what I have changed
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function (type, callback) {
var start = 100,
end = 0;
if (type) {
start = 0;
end = 100;
}
var si = setInterval(function () {
if (type) { // check whether to open or close animation
start++;
} else {
start--
}
div.style.maxHeight = start + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
callback.call(this); // do the callback function
}
var hidden = false;
but.onclick = function () {
animate(hidden, function () {
hidden = !hidden; // set hidden to opposite
});
}
/*make sure parent container has a height set or max height won't work*/
html, body {
height:100%;
margin:0;
padding:0;
}
div {
width: 300px;
height: 300px;
background-color: blue;
}
<div id="animation"></div>
<button id="toggle">Toggle</button>
Example Fiddle

Categories