javascript module with JQuery causing module functions to be undefined - javascript

I'm trying to make a module called ScrollToAnchor that has a function called goToTarget that I will be able to call like ScrollToAnchor.goToTarget(target);
However it says that
ScrollToAnchor.goToTarget is not a function
I think ScrollToAnchor is of type jQuery how I have it because of the $. Here is the code:
var ScrollToAnchor = $(function() {
var headerHeight = 70;
$('a[href*="#"]:not([href="#"])').click(function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
if (goToTarget(this.hash))
return false;
}
});
/*$('input[data-target]').click(function() {
if (gotoTarget($(this).data("target")))
return false;
})*/
var goToTarget = function(targetName) {
var target = $(targetName);
target = target.length ? target : $('[name="' + targetName.slice(1) + '"]');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - headerHeight
}, 1000);
return true;
}
return false;
}
return {
goToTarget: goToTarget
}
});
What am I doing wrong? If i remove the $ from var ScrollToAnchor = $(function () { then the jQuery inside ScrollToAnchor doesn't work.
But if I leave the $ there then it thinks ScrollToAnchor is type jQuery and ScrollToAnchor.goToTarget is not a function.

The $(function() {...}) is a short hand of $( document ).ready( handler ).
So the result of $(function() {...}) is a jQuery result set containing the document as element.
You are looking for event delegation:
$(document).on('click', 'a[href*="#"]:not([href="#"])', function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
if (goToTarget(this.hash))
return false;
}
});
This will ensure that the click event will be use for all a element no matter when they have been added to the DOM and allows your to make your goToTarget available in the global scope in an easy way. Your final code will then look this way:
var ScrollToAnchor = (function() {
var headerHeight = 70;
// event handler with delegation
$(document).on('click', 'a[href*="#"]:not([href="#"])', function() {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
if (goToTarget(this.hash))
return false;
}
});
function goToTarget(targetName) {
var target = $(targetName);
target = target.length ? target : $('[name="' + targetName.slice(1) + '"]');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - headerHeight
}, 1000);
return true;
}
return false;
}
return {
goToTarget: goToTarget
}
}());
Using event delegation there is no need to wrap you whole code into a $(function() {...}) and your ScrollToAnchor is public available.

Turn ScrollToAnchor into a normal function. This function will be in the global scope:
window.ScrollToAnchorFactory = function () {
var headerHeight = 70;
$('a[href*="#"]:not([href="#"])').click(function () {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
if (goToTarget(this.hash))
return false;
}
});
/*$('input[data-target]').click(function() {
if (gotoTarget($(this).data("target")))
return false;
})*/
var goToTarget = function (targetName) {
var target = $(targetName);
target = target.length ? target : $('[name="' + targetName.slice(1) + '"]');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - headerHeight
}, 1000);
return true;
}
return false;
}
return {
goToTarget: goToTarget
}
};
You could also use a module.export instead of putting this in the global scope, if you'd like to create a commonJS module out of this code. That would allow you to require() it into other files (using Browserify to compile).
If you do decide to just keep ScrollToAnchorFactory in the global scope, wherever you need to use scrollToAnchor.goToTarget (in the same file or a different one)...
$(function() {
var scrollToAnchor = window.ScrollToAnchorFactory();
// you can now use scrollToAnchor.goToTarget(target)
});
You'll want jQuery's DOM ready function wrapped around this part, so that ScrollToAnchorFactory doesn't try to init before your anchors are fully formed in the DOM.

Related

the hash link not matched with nav menu

when I click on navbar item the hash link scroll event not matched with the correct nav menu item
I tried to change the 'scrollto' variable up or down but the problem still exists
below is the code :
// Smooth scroll for the menu and links with .scrollto classes
var scrolltoOffset = $('#header').outerHeight() - 21;
var clicked = false;
$('.nav-menu a, #mobile-nav a, .scrollto').on('click', function(e) {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
debugger;
if (target.length) {
e.preventDefault();
var scrollto = target.offset().top - scrolltoOffset;
if ($(this).attr("href") == '#header') {
scrollto = 0;
}
$('html, body').animate({
scrollTop: scrollto
}, 1500, 'easeInOutExpo');
if ($(this).parents('.nav-menu').length) {
$('.nav-menu .menu-active').removeClass('menu-active');
$(this).closest('li').addClass('menu-active');
}
if ($('body').hasClass('mobile-nav-active')) {
$('body').removeClass('mobile-nav-active');
$('#mobile-nav-toggle i').toggleClass('fa-times fa-bars');
$('#mobile-body-overly').fadeOut();
}
return false;
}
}
});
this is the live site innovators.com
Easy fix. You are not scrolling enough.
Just scroll two pixels less: -21 => -23
// Smooth scroll for the menu and links with .scrollto classes
var scrolltoOffset = $('#header').outerHeight() - 23;
var clicked = false;
$('.nav-menu a, #mobile-nav a, .scrollto').on('click', function(e) {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
debugger;
if (target.length) {
e.preventDefault();
var scrollto = target.offset().top - scrolltoOffset;
if ($(this).attr("href") == '#header') {
scrollto = 0;
}
$('html, body').animate({
scrollTop: scrollto
}, 1500, 'easeInOutExpo');
if ($(this).parents('.nav-menu').length) {
$('.nav-menu .menu-active').removeClass('menu-active');
$(this).closest('li').addClass('menu-active');
}
if ($('body').hasClass('mobile-nav-active')) {
$('body').removeClass('mobile-nav-active');
$('#mobile-nav-toggle i').toggleClass('fa-times fa-bars');
$('#mobile-body-overly').fadeOut();
}
return false;
}
}
});

Sleep function before smooth scroll

How can I add a 3 seconds pause before the smooth scroll?
The user will click on the button, then there will be a sleep of 3 seconds and then the smooth scroll will run.
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
You could add an setTimeout() like so:
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
setTimeout(function(){
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
}, 3000);
return false;
}
}
});
});
You could use the JavaScript-standard setTimeout() function:
JavaScript
setTimeout(function () {
// function that is executed after the timer ends
}, 3000);
As you can see, the setTimeout function takes two parameters: a handler (function) that will be executed after the timer ends, and an integer, that defines the timer duration in milliseconds.
If you are unfamiliar with all this "handling" concept, consider the below example instead, where we do the same, but first "save" the function in a variable:
JavaScript
var fnCallback = function () {
console.log('This plague works.');
};
// Call setTimeout() with a handler function (fnCallback), and an integer (3000)
setTimeout(fnCallback, 3000);

Why does my if statement keep running?

I'm trying to make a browser scroll to a point on a page if the page is scrolled down. I'm using jQuery .bind() to bind html to mousewheel. Here's my code:
"use strict";
var scrollpoint = 1;
$(document).ready(function(){
console.log(scrollpoint);
$("#divacon").hide();
$("#divbcon").hide();
$('#div-a').waypoint(function() {
$("#divacon").fadeIn();
var scrollpoint = 2;
console.log("waypoint a reached");
},{context:"#container"});
$('#div-b').waypoint(function() {
$("#divbcon").fadeIn();
console.log("waypoint b reached");
},{context:"#container"});
and
$('html').bind('mousewheel', function(e){
var flag = true;
if(flag) {
if(e.originalEvent.wheelDelta < 0) {
if((scrollpoint == 1)) {
var target = $('#div-a');
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
var targetoffset = target.offset().top;
console.log(scrollpoint);
$('#container').animate(
{scrollTop: targetoffset},
400,
function(){
var scrollpoint = 2;
console.log(scrollpoint);
}
);
}
else if((scrollpoint = 2)){
//scroll down
console.log('2');
}
else{
//scroll down
console.log('Down');
}
}else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
flag = false;
}
});
What's happening is that my if statement is being called after the first time, even when flag = false;. What am I doing wrong? The site can be found live at http://wilsonbiggs.com/sandy
I think it has to be
var flag = true; //put the flag out side mouse wheel bind.
$('html').bind('mousewheel', function(e){
if(flag) {
Otherwise each time your even triggers you set flag to true and the following if condition will be satisfied always.

Javascript Smooth Scrolling - Not working with second click

I use the following script for a smooth scroll effect minus an amount of pixel on one page. The problem is, i click on one anchor link, the scroll effects works as it should but then i scroll back to the top of the page where the links are and click on another page. It doesnt work. I just copied the script from a webpage my javascript is very bad.
Thx for your help.
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
$('a[href*=#]').each(function() {
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
var $target = $(this.hash), target = this.hash;
if (target) {
var targetOffset = $target.offset().top - 70;
$(this).click(function(event) {
if(event != 'undefined') {
event.preventDefault();}
$(scrollElem).animate({scrollTop: targetOffset}, 400, function(e) {
e.preventDefault();
location.hash = target;
});
});
}
}
});
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
}
There's an error in the code.
Where it says:
$(scrollElem).animate({scrollTop: targetOffset}, 400, function(e) {
e.preventDefault();
location.hash = target;
});
You are calling preventDefault() on nothing. Leave it as this and it will work:
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
location.hash = target;
});
The error was at the beggining of the code. Instead of using an each loop, you should add a clickevent to the anchor elements. By using the each loop, you only add the click event once, and thus on the second click the event is undefined and the code runs into an error.
Here's your code rewritten as a click event:
$('a[href*=#]').click(function(e){
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath && (location.hostname == this.hostname || !this.hostname) && this.hash.replace(/#/,'') ) {
var $target = $(this.hash), target = this.hash;
if (target) {
var targetOffset = $target.offset().top - 70;
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
if( e != 'undefined' ) {
e.preventDefault();
}
location.hash = target;
});
}
}
});
Hope this helps ;-)

Smooth scroll script issue

I'm using a smooth scroll script for a site I'm currently working on, and I've got a really annoying problem what I've experienced before with the same script. It works nice and smoothly but when I click on one of the navigation points what should lead me to the div(or a) I'm trying to target, it shows me the targeting area for like 0.1 seconds, and then it starts to scroll. It doesn't happen everytime, but often enough to be annoying. How could I prevent this? Here is the script I'm talking about:
$(window).load(function(){
$(".contactLink").click(function(){
if ($("#contactForm").is(":hidden")){
$("#contactForm").slideDown("slow");
}
else{
$("#contactForm").slideUp("slow");
}
});
});
function closeForm(){
$("#messageSent").show("slow");
setTimeout('$("#messageSent").hide();$("#contactForm").slideUp("slow")', 2000);
}
$(window).load(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
$('a[href*=#]').each(function() {
if ( filterPath(location.pathname) == filterPath(this.pathname)
&& location.hostname == this.hostname
&& this.hash.replace(/#/,'') ) {
var $targetId = $(this.hash), $targetAnchor = $('[name=' + this.hash.slice(1) +']');
var $target = $targetId.length ? $targetId : $targetAnchor.length ? $targetAnchor : true;
if ($target) {
var targetOffset = $target.offset().top - 110;
$(this).click(function() {
$('html, body').animate({scrollTop: targetOffset}, 1400);
var d = document.createElement("div");
d.style.height = "101%";
d.style.overflow = "hidden";
document.body.appendChild(d);
window.scrollTo(0,scrollToM);
setTimeout(function() {
d.parentNode.removeChild(d);
}, 10);
return false;
});
}
}
});
});
setTimeout(function() {
d.parentNode.removeChild(d);
}, 10);
return false;
});
move the return false out of the setTimeOut
Found the solution:
$(this).click(function(e) {
e.preventDefault();
Now it rolls fine.

Categories