Jquery custom scrollspy active nav item - javascript

I'm trying to make a custom scrollspy for a website.
When scroll down I want first of all make the nav fixed/sticky, that works perfectly. When scroll down further I try to make the current nav item active, by adding a class active.
But whatever I try I just can't get that class active added to the nav item when we are at that specific section. I don't get any errors whatsoever so I rerally don't know anymore what I do wrong. I just can't see it.
Is this perhaps the wrong approach or can someone see why it won't get active?
$(function() {
var $anchor = $('.product-menu');
if ($anchor.length) {
var $menuItems = $anchor.find('a'),
$scrollItems = $menuItems.map(function() {
var item = $($(this).attr("href"));
if (item.length) {
return item;
}
}),
initPosition = $anchor.offset().top;
$(window).scroll(function() {
var htop = $('#header').outerHeight(true) - 1;
if (initPosition != $anchor.offset().top && !$anchor.hasClass('sticky')) {
initPosition = $anchor.offset().top;
}
if ($(window).scrollTop() >= initPosition - htop) {
$anchor.addClass("sticky").css({
top: htop
});
} else {
$anchor.removeClass("sticky");
}
if ($anchor.length && $(window).width() > 768) {
var cur = $scrollItems.map(function() {
if ($(window).scrollTop() >= $(this).offset().top - $anchor.outerHeight() - $('#header').outerHeight()) return this;
});
cur = cur[cur.length - 1];
var id = cur && cur.length ? cur[0].id : "";
$menuItems.removeClass("active").end().filter("[href='#" + id + "']").addClass("active");
}
});
}
});
#header {
background: indianred;
color: #fff;
height: 60px;
position: sticky;
top: 0;
z-index: 98;
transition: all ease-in-out .25s;
box-shadow: 0 5px 10px rgba(0,0,0,.05);
}
.product-menu {
margin: 45px 0;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
height:60px;
line-height:60px;
box-shadow: 0 5px 10px rgba(0,0,0,.05);
}
.product-menu.sticky {
position: sticky;
background: #fff;
z-index: 9;
width: 100%;
}
.list-inline {
padding-left: 0;
list-style: none;
display: flex;
flex-direction: row;
align-items: center;
margin: 0;
}
.list-inline li {
margin: 0 5px;
}
.product-block {
height: 300px;
background: #eee;
border: 1px solid #000;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<header id="header">
<div class="header flex flex-align-center flex-between container">
<div class="logo">
<img src="" alt="Logo" width="" height="64" />
</div>
</div>
<nav id="menu" class="nav list-inline">
<ul class="list-inline container">
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
</ul>
</nav>
</header>
<div class="some-container">
<nav class="product-menu">
<ul class="list-inline container">
<li>Product information</li>
<li>Specifications</li>
<li>Product bundles</li>
<li>Reviews</li>
<li>Related products</li>
</ul>
</nav>
<div class="desc">
<div id="description" class="product-block">description</div>
<div id="specifications" class="product-block">specifications</div>
</div>
<div class="info">
<div id="bundles" class="product-block">bundles</div>
<div id="reviews" class="product-block">reviews</div>
</div>
<div id="related" class="product-block">related</div>
</div>
</body>
</html>

This is pretty rough but might help you get you to where you want. Defiantly not the most efficient way to handle this.
I changed $(window).width() > 768 greater than value to 520 so example below would run in stackoverflow desktop.
I've include comments in my newly added code below...
$(function() {
// changed this to const variable and non object var
const anchor = $('.product-menu');
// set updatable vars on ready
let scrollTop = $(this).scrollTop();
let topOffset = anchor.outerHeight() + $('#header').outerHeight();
// if product menu nav exists
if (anchor.length) {
// re arranged vars a bit
let $menuItems = $('a', anchor);
let $scrollItems;
// update scroll items var
$scrollItems = $menuItems.map(function() {
let item = $($(this).attr("href"));
if (item.length) {
return item;
}
});
let initPosition = anchor.offset().top;
// added this so when product menu items are clicked it scrolls to div
$menuItems.on('click', function(e) {
// get the href id from the clicked anchor
let anchor = $(this).attr('href');
// get the scroll to (top) position minus the nav
let scrollTo = $(anchor).offset().top - topOffset;
// scroll too
$('html,body').animate({
scrollTop: scrollTo
}, 1000);
// prevent link defaults
e.preventDefault();
});
// changed this to .on binding method instead of .scroll
$(window).on('scroll', function() {
let htop = $('#header').outerHeight(true) - 1;
if (initPosition != anchor.offset().top && !anchor.hasClass('sticky')) {
initPosition = anchor.offset().top;
}
if ($(window).scrollTop() >= initPosition - htop) {
anchor.addClass("sticky").css({
top: htop
});
} else {
anchor.removeClass("sticky");
}
// update vars on scroll
scrollTop = $(this).scrollTop();
topOffset = anchor.outerHeight() + $('#header').outerHeight();
// changed 768 to 520 so stackoverflow demo would fire
if (anchor.length && $(window).width() > 520) {
// each scroll items for key value function
$.each($scrollItems, function(key, value) {
// if the top offset minus the scroll top position is less than or equal to header + product menu height
if ((value.offset().top - scrollTop) <= topOffset) {
// remove class from all product menu item anchors
$menuItems.removeClass('active');
// add active class to current viewed product menu anchor
$('a[href="#' + this.attr('id') + '"]', anchor).addClass('active');
}
});
}
});
}
});
#header {
background: indianred;
color: #fff;
height: 60px;
position: sticky;
top: 0;
z-index: 98;
transition: all ease-in-out .25s;
box-shadow: 0 5px 10px rgba(0, 0, 0, .05);
}
.product-menu {
margin: 45px 0;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
height: 60px;
line-height: 60px;
box-shadow: 0 5px 10px rgba(0, 0, 0, .05);
}
.product-menu.sticky {
position: sticky;
background: #fff;
z-index: 9;
width: 100%;
}
.list-inline {
padding-left: 0;
list-style: none;
display: flex;
flex-direction: row;
align-items: center;
margin: 0;
}
.list-inline li {
margin: 0 5px;
}
.product-block {
height: 300px;
background: #eee;
border: 1px solid #000;
}
.product-menu a.active {
color: indianred;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<header id="header">
<div class="header flex flex-align-center flex-between container">
<div class="logo">
<img src="" alt="Logo" width="" height="64" />
</div>
</div>
<nav id="menu" class="nav list-inline">
<ul class="list-inline container">
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
</ul>
</nav>
</header>
<div class="some-container">
<nav class="product-menu">
<ul class="list-inline container">
<li>Product information</li>
<li>Specifications</li>
<li>Product bundles</li>
<li>Reviews</li>
<li>Related products</li>
</ul>
</nav>
<div class="desc">
<div id="description" class="product-block">description</div>
<div id="specifications" class="product-block">specifications</div>
</div>
<div class="info">
<div id="bundles" class="product-block">bundles</div>
<div id="reviews" class="product-block">reviews</div>
</div>
<div id="related" class="product-block">related</div>
</div>
</body>
</html>

After some minor modifications only in this part of your code.
if ($anchor.length && $(window).width() > 768) {
...
}
The menu element will remain active while scrolling in the area covered by the element's height, you can check the desired behavior by running the code snippet below:
$(function() {
var $anchor = $('.product-menu');
if ($anchor.length) {
var $menuItems = $anchor.find('a'),
$scrollItems = $menuItems.map(function() {
var item = $($(this).attr("href"));
if (item.length) {
return item;
}
}),
initPosition = $anchor.offset().top;
$(window).scroll(function() {
var htop = $('#header').outerHeight(true) - 1;
if (initPosition != $anchor.offset().top && !$anchor.hasClass('sticky')) {
initPosition = $anchor.offset().top;
}
if ($(window).scrollTop() >= initPosition - htop) {
$anchor.addClass("sticky").css({
top: htop
});
} else {
$anchor.removeClass("sticky");
}
if ($anchor.length) {
Array.from($scrollItems).forEach(($scrollItem, i) => {
let id = $($scrollItem).attr('id');
let bottomOffsetMargin;
if(i < $scrollItems.length -1 ) {
bottomOffsetMargin = $($scrollItems[i+1]).offset().top;
} else {
bottomOffsetMargin = $anchor.offset().top + $anchor.outerHeight();
}
if ($(window).scrollTop() >= $($scrollItem).offset().top && $(window).scrollTop() < bottomOffsetMargin && !$anchor.find("a[href='#" + id + "']").hasClass("active")) {
$menuItems.removeClass("active");
$anchor.find("a[href='#" + id + "']").addClass("active");
}
});
}
});
}
});
#header {
background: indianred;
color: #fff;
height: 60px;
position: sticky;
top: 0;
z-index: 98;
transition: all ease-in-out .25s;
box-shadow: 0 5px 10px rgba(0, 0, 0, .05);
}
.product-menu {
margin: 45px 0;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
height: 60px;
line-height: 60px;
box-shadow: 0 5px 10px rgba(0, 0, 0, .05);
}
.product-menu.sticky {
position: sticky;
background: #fff;
z-index: 9;
width: 100%;
}
.list-inline {
padding-left: 0;
list-style: none;
display: flex;
flex-direction: row;
align-items: center;
margin: 0;
}
.list-inline li {
margin: 0 5px;
}
.product-block {
height: 500px;
background: #eee;
border: 1px solid #000;
}
a.goSmoothly.active {
text-decoration: none;
color: red;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<header id="header">
<div class="header flex flex-align-center flex-between container">
<div class="logo">
<img src="" alt="Logo" width="" height="64" />
</div>
</div>
<nav id="menu" class="nav list-inline">
<ul class="list-inline container">
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
<li>Main nav item</li>
</ul>
</nav>
</header>
<div class="some-container">
<nav class="product-menu">
<ul class="list-inline container">
<li>Product information</li>
<li>Specifications</li>
<li>Product bundles</li>
<li>Reviews</li>
<li>Related products</li>
</ul>
</nav>
<div class="desc">
<div id="description" class="product-block">description</div>
<div id="specifications" class="product-block">specifications</div>
</div>
<div class="info">
<div id="bundles" class="product-block">bundles</div>
<div id="reviews" class="product-block">reviews</div>
</div>
<div id="related" class="product-block">related</div>
</div>
</body>
</html>

Related

Drop Down direction changes according to free space

I am just into programing and I need your help.
I have an issue with my drop down sub-menu-s. I have a simple drop down on my header, however it is located too close to window border in this case only(Depending on permissions).
So the sub-menu opens beyond window border to the right side and user doesn't see the content of it.
I want it to detect if there is enough space to open on the right side. If yes, open on right. If not open on the left. Could you please help me to solve this issue?
This is how it works when it has enough space.
Here is my html:
<ul class="main-menu-list">
<li class="header-dropdown-item">
<span class="header-dropdown-item-title">Admin</span>
<img src="../Layout/images//arrow-down.svg" alt="">
<ul class="sub-menu-list">
<li class="header-dropdown-item">
<a class="arrow-right header-dropdown-item-title">Users</a>
<ul class="sub-menu-list-right">
<li>
<a class="header-sub-menu-item">New
users</a>
</li>
<li>
<a class="header-sub-menu-item">Users
management</a>
</li>
<li>
<a class="header-sub-menu-item" >Contacts List</a>
</li>
</ul>
</li>
<li class="header-dropdown-item">
<a class="arrow-right header-dropdown-item-title">Security</a>
<ul class="sub-menu-list-right">
<li>
<a class="header-sub-menu-item" >Roles</a>
</li>
<li>
<a class="header-sub-menu-item" >Roles and
Permissions</a>
</li>
<li>
<a class="header-sub-menu-item" >Column Based
Security</a>
</li>
</ul>
</li>
<li class="header-dropdown-item">
<a class="arrow-right header-dropdown-item-title">Notifications Management</a>
<ul class="sub-menu-list-right">
<li>
<a class="header-sub-menu-item"
>Email Notifications</a>
</li>
<li>
<a class="header-sub-menu-item" >Sent Email
Notifications</a>
</li>
</ul>
</li>
<li class="header-dropdown-item">
<a class="arrow-right header-dropdown-item-title">Source Data Analysis</a>
<ul class="sub-menu-list-right">
<li>
<a class="header-sub-menu-item" >Automated
Error Logging</a>
</li>
</ul>
</li>
<li class="header-dropdown-item">
<a class="arrow-right header-dropdown-item-title">Technical Services</a>
<ul class="sub-menu-list-right">
<li>
<a class="header-sub-menu-item" >Dropdown Lists</a>
</li>
<li>
<a class="header-sub-menu-item" >Unconventional
Tags</a>
</li>
<li>
<a class="header-sub-menu-item"
>Tag Matching Duplicates</a>
</li>
<li>
<a class="header-sub-menu-item" >3 Digit Code
Register</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Here is my CSS:
.sub-menu
background-color: header-sub-menu-background-color;
color: header-sub-menu-color;
display: flex;
justify-content: flex-end;
height: header-sub-menu-height;
padding-right: page-side-padding;
span
margin: 10px 0;
display: inline-block;
cursor: pointer;
ul
margin: 0;
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
font-family: font-default-content;
font-size: font-size-ssm;
font-weight: bold;
text-transform: uppercase;
padding: 0;
li
& + li
margin-left: 30px;
a
cursor: pointer;
ul
& > li:hover
& > a,
& > span
color: header-menu-active-color;
> .arrow-right:after
border-left-color: header-menu-active-color;
> .sub-menu-list
shown()
> .sub-menu-list-right
showImmediately()
li
.arrow-right
cursor: default;
&:after
pointer-events: none;
position: absolute;
content: "";
width: 0;
height: 0;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
border-left: 3px solid gray-color-3;
display: inline-block;
vertical-align: middle;
right: 12px;
top: 0;
bottom: 0;
margin: auto;
a:hover, span:hover
color: header-menu-active-color;
.main-menu-list li
position: relative;
.sub-menu-list, .sub-menu-list-right
hidden()
display: inline-block;
list-style: none;
position: absolute;
background-color: black-color-1;
top: 31px;
left: -15px;
z-index: $main-menu-sub-menu-list-zindex;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
li
position: relative;
white-space:nowrap;
margin-left: 0;
:hover > .sub-menu-list-right
shown()
a
width: 100%;
font-family: font-default-content;
font-size: 10px;
font-weight: 700;
padding: 10px 32px 10px 15px;
display: inline-block;
&:hover
color: header-menu-active-color;
p:hover
color: header-menu-active-color;
.sub-menu-list
min-width: 100%;
hideWithDelay()
a
text-decoration: none;
display: inline-block;
color: gray-color-3;
.active
color: header-menu-active-color;
.sub-menu-list-right
top: 0;
left: 100%;
&:hover
.sub-menu-list
shown()
&:hover
shown()
.sub-menu-list-right
&:hover
shown()
span
background-color: black-color-1
.main-menu-list
li:first-child:nth-last-child(2)
li:first-child:nth-last-child(3)
.sub-menu-list-right
left: auto;
right: 100%;
And Pure JS:
<script type="text/javascript">
(function () {
handleMenuItems();
// functions:
function handleMenuItems() {
var menuEl = document.querySelector(".menu"),
userLinksList = menuEl && menuEl.querySelector(".user-links"),
recentlyItemListEl = menuEl && menuEl.querySelector(".recently-visited-item"),
favoriteItemListEl = menuEl && menuEl.querySelector(".favorites-item");
if (userLinksList) {
userLinksList.addEventListener("mouseover", function (evt) {
var options = {
url: "/api/userlinks",
method: "GET",
successCallback: onloadUserLinks
};
function onloadUserLinks(result) {
if (!window.__RAPMD__) {
window.__RAPMD__ = {};
}
window.__RAPMD__.lastUserLinks = result;
createMenuList(result.RecentLinks, recentlyItemListEl, "No recently visited pages");
createMenuList(result.Favorites, favoriteItemListEl, "No favorite pages");
}
if (!window.__RAPMD__ || !window.__RAPMD__.lastUserLinks) {
ajax(options);
}
});
userLinksList.addEventListener("mouseleave", function (evt) {
if (!window.__RAPMD__) {
return;
}
window.__RAPMD__.lastUserLinks = null;
});
}
}
function createMenuList(items, menuItemEl, emptyListTitle) {
if (!menuItemEl) {
return;
}
var df = document.createDocumentFragment();
(items.length ? items : [{ Title: emptyListTitle }]).forEach(function (item) {
var li = document.createElement("li"),
a = document.createElement("a");
if (item.Url) {
a.href = item.Url;
} else {
a.classList.add("empty-link-item");
}
a.innerHTML = item.Title;
li.appendChild(a);
df.appendChild(li);
});
menuItemEl.textContent = "";
menuItemEl.appendChild(df);
}
function ajax(options) {
var url = options.url,
method = options.method,
successCallback = options.successCallback,
failureCallback = options.failureCallback,
xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (xhr.status === 200 && successCallback) {
var response = JSON.parse(xhr.responseText);
successCallback(response);
} else if (failureCallback) {
failureCallback();
}
};
xhr.send();
}
})();
</script>
I don't think there is an easy CSS way to solve this. The only option I can think about is to align it to the left if the space is not enough. You can use the document.querySelector("#sub-menu").getBoundingClientRect() function to get the position of the element.
{
"x": 1261.5,
"y": -309,
"width": 298,
"height": 452,
"top": -309,
"right": 1559.5,
"bottom": 143,
"left": 1261.5
}
Then you can check if the sub-menu would overflow out of the page and assign a class that makes it align to the left instead of the right.
const subMenuBound = document.querySelector("#sub-menu").getBoundingClientRect();
const windowWidth = document.getElementsByTagName("body")[0].clientWidth;
const subMenuX = subMenuBound.x;
const subMenuWidth = subMenuBound.width;
if (subMenuBound.width + subMenuBound.x > windowWidth) {
// assign a class to the sub-menu to
// align to the left instead of right
} else {
// remove the class
}

When click on second dropdown black box should remain visible

In this dropdown nav I'm building if a dropdown is opened and you click to open a second one, the black box should remain visible. At the moment the black box disappears when you click on a second dropdown and reappears after the dropdown is completely opened.
Update
I also noticed the black box shows after a dropdown is open and it should open at the same time.
I hope this makes sense and thank you for your help!
$(document).ready(function() {
$(".click").on("click", function(e) {
var menu = $(this);
toggleDropDown(menu);
});
$(document).on('mouseup',function(e) {
var container = $("nav .top-bar-section ul");
// if the target of the click isn't the container nor a descendant of the container
if (!container.is(e.target) && container.has(e.target).length === 0) {
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
$(".main-container").removeClass("black-bg");
if ($('a.active').hasClass('active')) {
$('a.active').removeClass('active');
}
});
}
});
});
function toggleDropDown(menu) {
var isActive = $('a.active').length;
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
$(".main-container").removeClass("black-bg");
if (menu.hasClass('active')) {
menu.removeClass('active');
} else {
$('a.active').removeClass('active');
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
});
if (!isActive) {
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.nav-wrapper {
width: 100%;
overflow: hidden;
background: #424242;
}
nav {
width: 1024px;
margin: auto;
overflow: hidden;
background: #424242;
}
.nav-content {
width: 100%;
z-index: 999;
background: #ccc;
}
.top-bar-section {
float: left;
}
.top-bar-section a.active {
background: #f00;
}
.showup {
display: none;
background: #ccc;
position: absolute;
width: 100%;
top: 70px;
left: 0;
z-index: 99;
padding: 30px 15px 30px 20px;
}
p {
font-size: 14px;
line-height: 1.4;
}
li.nav-item {
display: inline-block;
background: #f5f5f5;
}
li.nav-item a {
display: block;
text-decoration: none;
padding: 10px;
}
.main-container {
width: 80%;
height: 400px;
margin: auto;
}
.black-bg {
background: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav-wrapper">
<nav>
<div class="top-bar-section">
<ul>
<li class="nav-item">
Nav item 1
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 1.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 2
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 2.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 3
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 3.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 4
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 4.
</p>
</div>
</div>
</li>
</ul>
</div>
</nav>
</div>
<div class="main-container">
</div>
If you want black-bg being added once the menu is clicked, then do not remove and add black-bg class on every click event. Simply add it once if the menu have active class and remove it when menu do not active class. If you remove and add class on every click event then black-bg will first disappear and again it will appear. To black-bg at the time drop-down is open then remove $(".main-container").addClass("black-bg"); from callback function of slideDown() because a callback function is executed after the current effect is finished.
$(document).ready(function() {
$(".click").on("click", function(e) {
var menu = $(this);
toggleDropDown(menu);
});
$(document).on('mouseup',function(e) {
var container = $("nav .top-bar-section ul");
// if the target of the click isn't the container nor a descendant of the container
if (!container.is(e.target) && container.has(e.target).length === 0) {
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
$(".main-container").removeClass("black-bg");
if ($('a.active').hasClass('active')) {
$('a.active').removeClass('active');
}
});
}
});
});
function toggleDropDown(menu) {
var isActive = $('a.active').length;
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
if (menu.hasClass('active')) {
menu.removeClass('active');
$(".main-container").removeClass("black-bg");
} else {
$('a.active').removeClass('active');
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
});
}
});
if (!isActive) {
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500);
$(".main-container").addClass("black-bg");
}
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.nav-wrapper {
width: 100%;
overflow: hidden;
background: #424242;
}
nav {
width: 1024px;
margin: auto;
overflow: hidden;
background: #424242;
}
.nav-content {
width: 100%;
z-index: 999;
background: #ccc;
}
.top-bar-section {
float: left;
}
.top-bar-section a.active {
background: #f00;
}
.showup {
display: none;
background: #ccc;
position: absolute;
width: 100%;
top: 70px;
left: 0;
z-index: 99;
padding: 30px 15px 30px 20px;
}
p {
font-size: 14px;
line-height: 1.4;
}
li.nav-item {
display: inline-block;
background: #f5f5f5;
}
li.nav-item a {
display: block;
text-decoration: none;
padding: 10px;
}
.main-container {
width: 80%;
height: 400px;
margin: auto;
}
.black-bg {
background: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav-wrapper">
<nav>
<div class="top-bar-section">
<ul>
<li class="nav-item">
Nav item 1
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 1.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 2
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 2.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 3
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 3.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 4
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 4.
</p>
</div>
</div>
</li>
</ul>
</div>
</nav>
</div>
<div class="main-container">
</div>
Just move $(".main-container").removeClass("black-bg"); into if (menu.hasClass('active')) {
$(document).ready(function() {
$(".click").on("click", function(e) {
var menu = $(this);
toggleDropDown(menu);
});
$(document).on('mouseup',function(e) {
var container = $("nav .top-bar-section ul");
// if the target of the click isn't the container nor a descendant of the container
if (!container.is(e.target) && container.has(e.target).length === 0) {
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
$(".main-container").removeClass("black-bg");
if ($('a.active').hasClass('active')) {
$('a.active').removeClass('active');
}
});
}
});
});
function toggleDropDown(menu) {
var isActive = $('a.active').length;
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
//$(".main-container").removeClass("black-bg"); FROM HERE
if (menu.hasClass('active')) {
menu.removeClass('active');
$(".main-container").removeClass("black-bg"); // TO HERE
} else {
$('a.active').removeClass('active');
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
});
if (!isActive) {
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.nav-wrapper {
width: 100%;
overflow: hidden;
background: #424242;
}
nav {
width: 1024px;
margin: auto;
overflow: hidden;
background: #424242;
}
.nav-content {
width: 100%;
z-index: 999;
background: #ccc;
}
.top-bar-section {
float: left;
}
.top-bar-section a.active {
background: #f00;
}
.showup {
display: none;
background: #ccc;
position: absolute;
width: 100%;
top: 70px;
left: 0;
z-index: 99;
padding: 30px 15px 30px 20px;
}
p {
font-size: 14px;
line-height: 1.4;
}
li.nav-item {
display: inline-block;
background: #f5f5f5;
}
li.nav-item a {
display: block;
text-decoration: none;
padding: 10px;
}
.main-container {
width: 80%;
height: 400px;
margin: auto;
}
.black-bg {
background: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav-wrapper">
<nav>
<div class="top-bar-section">
<ul>
<li class="nav-item">
Nav item 1
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 1.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 2
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 2.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 3
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 3.
</p>
</div>
</div>
</li>
<li class="nav-item">
Nav item 4
<div class="showup">
<div class="nav-content">
<p>
Dropdown for Nav Item 4.
</p>
</div>
</div>
</li>
</ul>
</div>
</nav>
</div>
<div class="main-container">
</div>
Is this what you are looking for?
$(document).ready(function() {
$(".click").on("click", function(e) {
var menu = $(this);
toggleDropDown(menu);
});
$(document).on('mouseup',function(e) {
var container = $("nav .top-bar-section ul");
// if the target of the click isn't the container nor a descendant of the container
if (!container.is(e.target) && container.has(e.target).length === 0) {
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
$(".main-container").removeClass("black-bg");
if ($('a.active').hasClass('active')) {
$('a.active').removeClass('active');
}
});
}
});
});
function toggleDropDown(menu) {
var isActive = $('a.active').length;
$('a.active').parent().find('.showup').stop(true, true).slideUp(500, function() {
if (menu.hasClass('active')) {
menu.removeClass('active');
} else {
$('a.active').removeClass('active');
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
});
if (!isActive) {
menu.addClass('active');
menu.parent().find('.showup').stop(true, true).slideDown(500, function() {
$(".main-container").addClass("black-bg");
});
}
The black box will remain there in this case. What you were previously doing was that you were removing black-box explicitly.

Added $(box).bind("click touchstart", function() { to my logic but not successful on iPad

I have added '$(box).bind("click touchstart", function() {' to my script but still not running on iPad. I'm trying to get this script to work across all devices so that user can select the box nunbers 1-8 and recommendation with a border will show below. any idea why this is breaking on iPad? is there a better way to structure this?
var numbers = document.querySelectorAll(".clicked");
var letters = document.querySelectorAll(".border");
numbers.forEach(function(box, index) {
$(box).bind("click touchstart", function() {
letters.forEach(function(box) {
box.classList.remove("showBorder");
});
var info = document.getElementsByClassName('box-tip')[0];
if (index > 2) {
info.style.left = 11 + ((index - 3) * 45) + 'px';
}
else {
info.style.left = 0 + 'px';
}
info.style.visibility = 'visible';
letters[index].classList.add("showBorder");
});
$(document).on("click", '.clicked', function(){
$('.clicked').removeClass('selected');
$(this).addClass('selected');
});
});
.list-box li {display: inline-block;list-style-type: none;padding: 1em;background:red;}
.list-box {margin:15px auto;padding:0;}
.box-sleeve li {display: inline-block;list-style-type: none;padding: 1em;background:red;}
.box-sleeve {margin:15px auto;padding:0;}
.showBorder { outline: 1px dashed #233354; outline-offset:1px;}
.box-tip {
display:inline;
margin: auto;
position: relative;
visibility: hidden;
padding-left:10px;
}
.numberCircle {
border-radius: 90%;
font-size: 12px;
border: 2px solid #000;
color: #fff;
background: #000;
padding: 0 4px;
}
.numberCircle span {
text-align: center;
display: block;
}
li.selected {color:#fff;background-color:#000;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>Test some logic one</span>
<ul class="list-box">
<li class="clicked">1</li>
<li class="clicked">2</li>
<li class="clicked">3</li>
<li class="clicked">4</li>
<li class="clicked">5</li>
<li class="clicked">6</li>
<li class="clicked">7</li>
<li class="clicked">8</li>
</ul>
<div>
<span>Test some logic two</span>
</div>
<div class="box-tip">
<span>Regular length for your collar size</span>
<span class="numberCircle">?</span>
</div>
<ul class="box-sleeve">
<li class="border">a</li>
<li class="border">b</li>
<li class="border">c</li>
<li class="border">d</li>
<li class="border">e</li>
<li class="border">f</li>
<li class="border">g</li>
<li class="border">h</li>
</ul>
Try the following tweaks:
Detect & store user agent first ua = navigator.userAgent;
Then match it with iPad's and store it event = (ua.match(/iPad/i)) ? "touchstart" : "click";.
Use as $(box).bind(event, function() { //do stuff });.
Working on iPad Air.
var numbers = document.querySelectorAll(".clicked"),
letters = document.querySelectorAll(".border"),
ua = navigator.userAgent,
event = (ua.match(/iPad/i)) ? "touchstart" : "click";
numbers.forEach(function(box, index) {
$(box).bind(event, function() {
letters.forEach(function(box) {
box.classList.remove("showBorder");
});
var info = document.getElementsByClassName('box-tip')[0];
if (index > 2) {
info.style.left = 11 + ((index - 3) * 45) + 'px';
} else {
info.style.left = 0 + 'px';
}
info.style.visibility = 'visible';
letters[index].classList.add("showBorder");
});
$(document).on("click", '.clicked', function() {
$('.clicked').removeClass('selected');
$(this).addClass('selected');
});
});
.list-box li {
display: inline-block;
list-style-type: none;
padding: 1em;
background: red;
}
.list-box {
margin: 15px auto;
padding: 0;
}
.box-sleeve li {
display: inline-block;
list-style-type: none;
padding: 1em;
background: red;
}
.box-sleeve {
margin: 15px auto;
padding: 0;
}
.showBorder {
outline: 1px dashed #233354;
outline-offset: 1px;
}
.box-tip {
display: inline;
margin: auto;
position: relative;
visibility: hidden;
padding-left: 10px;
}
.numberCircle {
border-radius: 90%;
font-size: 12px;
border: 2px solid #000;
color: #fff;
background: #000;
padding: 0 4px;
}
.numberCircle span {
text-align: center;
display: block;
}
li.selected {
color: #fff;
background-color: #000;
}
/* add these to prevent text move below 768 viewports */
#media (max-width: 768px) {
.box-tip span {
position: fixed;
left: 10px;
}
.box-tip span.numberCircle {
position: fixed;
left: 236px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>Test some logic one</span>
<ul class="list-box">
<li class="clicked">1</li>
<li class="clicked">2</li>
<li class="clicked">3</li>
<li class="clicked">4</li>
<li class="clicked">5</li>
<li class="clicked">6</li>
<li class="clicked">7</li>
<li class="clicked">8</li>
</ul>
<div>
<span>Test some logic two</span>
</div>
<div class="box-tip">
<span>Regular length for your collar size</span>
<span class="numberCircle">?</span>
</div>
<ul class="box-sleeve">
<li class="border">a</li>
<li class="border">b</li>
<li class="border">c</li>
<li class="border">d</li>
<li class="border">e</li>
<li class="border">f</li>
<li class="border">g</li>
<li class="border">h</li>
</ul>

dynamic fields class change per list element and Js to recognize part of the class

class in the list element change per box and are dynamic fields with width and length being the difference between the two. How to run my JS so that only the first part of the class is recognized without the number so js variable selectors should be '.attribute__swatch--width-' and '.attribute__swatch--length-'. please see my code below:
var numbers = document.querySelectorAll(".attribute__swatch--width-"),
letters = document.querySelectorAll(".attribute__swatch--length-"),
ua = navigator.userAgent,
event = (ua.match(/iPad/i)) ? "touchstart" : "click";
numbers.forEach(function(box, index) {
$(box).on(event, function() {
letters.forEach(function(box) {
box.classList.remove("showBorder");
});
var info = document.getElementsByClassName('box-tip')[0];
if (index > 2) {
info.style.left = 11 + ((index - 3) * 45) + 'px';
} else {
info.style.left = 0 + 'px';
}
info.style.visibility = 'visible';
letters[index].classList.add("showBorder");
});
$(document).on("click", '.clicked', function() {
$('.clicked').removeClass('selected');
$(this).addClass('selected');
});
});
.list-box li {display: inline-block;list-style-type: none;padding: 1em;background:red;}
.list-box {margin:15px auto;padding:0;}
.box-sleeve li {display: inline-block;list-style-type: none;padding: 1em;background:red;}
.box-sleeve {margin:15px auto;padding:0;}
.showBorder { outline: 1px dashed #233354; outline-offset:1px;}
.box-tip {
display:inline;
margin: auto;
position: relative;
visibility: hidden;
padding-left:10px;
}
.numberCircle {
border-radius: 90%;
font-size: 12px;
border: 2px solid #000;
color: #fff;
background: #000;
padding: 0 4px;
}
.numberCircle span {
text-align: center;
display: block;
}
li.selected {color:#fff;background-color:#000;}
#media (max-width: 768px) {
.box-tip span {
position: fixed;
left: 10px;
}
.box-tip span.numberCircle {
position: fixed;
left: 236px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>Test some logic one width</span>
<ul class="list-box">
<li class="attribute__swatch--width-14.5">1</li>
<li class="attribute__swatch--width-15">2</li>
<li class="attribute__swatch--width-15.5">3</li>
<li class="attribute__swatch--width-16">4</li>
<li class="attribute__swatch--width-16.5">5</li>
<li class="attribute__swatch--width-17">6</li>
<li class="attribute__swatch--width-17.5">7</li>
<li class="attribute__swatch--width-18">8</li>
</ul>
<div>
<span>Test some logic two length</span>
</div>
<div class="box-tip">
<span>Regular length for your collar size</span>
<span class="numberCircle">?</span>
</div>
<ul class="box-sleeve">
<li class="attribute__swatch--length-32">a</li>
<li class="attribute__swatch--length-34">b</li>
<li class="attribute__swatch--length-36">c</li>
<li class="attribute__swatch--length-38">d</li>
<li class="attribute__swatch--length-40">e</li>
<li class="attribute__swatch--length-42">f</li>
<li class="attribute__swatch--length-44">g</li>
<li class="attribute__swatch--length-46">h</li>
</ul>
You can use attribute selectors, specifically starts with (^=) to match:
document.querySelectorAll('[class^="attribute__swatch--width-"]');
document.querySelectorAll('[class^="attribute__swatch--length-"]')

Script works in html but not in javascript file

Final Update The problem got solved. Thank you all. Prepros compile my js file into main-dist. the new code was in there instead of my main.js. Thank you for all who help me.
update Able to reproduce the nonworking code in jsBin
I'm wondering why the function is not working in my js file after my jquery file is called but the script work in my HTML file.
I want the function to be in my js file so it isn't in each one of my HTML file.
Example 1 in html on jsFiddle
Example 2 in html
var navBar = function() {
var pull = $('#pull');
var menu = $('nav ul');
$(pull).on('click', function(e) {
e.preventDefault();
menu.slideToggle();
});
$(window).resize(function(){
var w = $(window).width();
if(w > 320 && menu.is(':hidden')) {
menu.removeAttr('style');
}
});
};
$(document).ready(navBar);
Really Long snippet. The navbar code work in snippet as well but it doesn't work when i load in my browser
//time on front page
function displayTime () {
var elt = document.getElementById("clock");
var now = new Date();
elt.innerHTML = now.toLocaleTimeString();
setTimeout (displayTime, 1000);
};
displayTime();
/*
function menu(){
$('.tMenu').click(function(){
$('nav ul').slideToggle();
})
}
menu(); */
var navBar = function() {
var pull = $('#pull');
var menu = $('nav ul');
$(pull).on('click', function(e) {
e.preventDefault();
menu.slideToggle();
});
$(window).resize(function(){
var w = $(window).width();
if(w > 320 && menu.is(':hidden')) {
menu.removeAttr('style');
}
});
};
$(document).ready(navBar);
//slider main page
var main = function(){
$('.arrow-next').click(function(){
var currentSlide = $('.active-slide');
var nextSlide = currentSlide.next();
var currentDot = $('.active-dot');
var nextDot = currentDot.next();
if (nextSlide.length === 0) {
nextSlide = $('.slide').first();
nextDot = $('.dot').first();
}
currentSlide.fadeOut(500).removeClass('active-slide');
nextSlide.fadeIn(500).addClass('active-slide');
currentDot.removeClass('active-dot');
nextDot.addClass('active-dot');
});
$('.arrow-prev').click(function(){
var currentSlide = $('.active-slide');
var prevSlide = currentSlide.prev();
var currentDot = $('.active-dot');
var prevDot = currentDot.prev();
if(prevSlide.length === 0) {
prevSlide = $('.slide').last();
prevDot = $('.dot').last();
}
currentSlide.fadeOut(500).removeClass('active-slide');
prevSlide.fadeIn(500).addClass('active-slide');
currentDot.removeClass('active-dot');
prevDot.addClass('active-dot');
});
$('.dot').click(function(){
var index = $(this).index(); // get the index or position of the current element that has the class .dot
$('.slide').fadeOut(500); // to hide all elements with class .slide
$('.dot').removeClass('active-dot');
$('.slide').removeClass('active-slide').addClass('active');
$('#slide' + (index+1)).fadeIn(500);
$('#slide' + (index+1)).removeClass('active').addClass('active-slide');
$(this).addClass('active-dot');
});
};
$(document).ready(main);
.clearfix:before,
.clearfix:after {
content: ' ';
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
zoom: 1;
}
nav {
background: #17181D;
border-bottom: 1px solid #0A0A0A;
font-family: 'PT Sans', Arial, sans-serif;
font-weight: bold;
position: relative;
height: 40px;
width: 100%;
}
nav ul {
height: 40px;
width: 600px;
margin: 0 auto;
padding: 0;
}
nav li {
display: inline;
float: left;
}
nav a {
color: #DED6D6;
display: inline-block;
line-height: 40px;
text-align: center;
text-decoration: none;
text-shadow: 1px 1px 0px #30365E;
width: 150px;
}
nav li a {
border-right: 1px solid #515676;
border-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
nav li:last-child a {
border-right: 0;
}
nav a:hover, nav a:active {
background-color: #2575C6;
}
nav a#pull {
display: none;
}
#media screen and (max-width: 600px) {
nav {
height: auto;
}
nav ul {
width: 100%;
display: block;
height: auto;
}
nav li {
width: 50%;
float: left;
position: relative;
}
nav li a {
border-bottom: 1px solid #C0C0C0;
border-right: 1px solid #C0C0C0;
}
nav a {
text-align: center;
width: 100%;
text-indent: 25px;
}
}
#media only screen and (max-width: 480px) {
nav {
border-bottom: 0;
}
nav ul {
display: none;
height: auto;
}
nav a#pull {
display: block;
background-color: #17181D;
width: 100%;
position: relative;
text-decoration: none;
}
nav a#pull:after {
border-top: .5em double white;
border-bottom: .145em solid white;
content: ' ';
display: inline-block;
height: 0.85em;
width: 1em;
position: absolute;
right: 15px;
top: 13px;
}
}
#media only screen and (max-width: 320px) {
nav li {
display: block;
float: none;
width: 100%;
}
nav li a {
border-bottom: 1px solid white;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<header>
<div>
<h1 class='vb'></h1>
<div class='time'></div>
<div id='clock'></div>
<nav class='clearfix'>
<ul class='clearfix'>
<li>
Home
</li>
<li>
Bio
</li>
<li>
Hobbies
</li>
<li>
Resume
</li>
</ul>
<a href='#' id='pull'>Menu</a>
</nav>
</div>
</header>
<div class='slider container'>
<div class='slide active-slide slide-bg' id='slide1'>
<div class='container'>
<div class='row'>
<div class='slide-copy-1 col-xs-12'>
<h1>Surrounding</h1>
<p class='fun'>Our lives are so hectic with everyday work, business and errands that we tend to never stop and take in our surrounding. When was the last time you stop and enjoy a nice beatiful sunset?</p>
</div>
</div>
</div>
</div>
<div class='slide' id='slide2'>
<div class='container'>
<div class='row'>
<div class='slide-copy col-xs-5'>
<h1>Get Moving And Motivated!</h1>
<p>In a world where digital devices is so prominent, we get lost in them. Our strength are that we are very adaptable but it can also be our greatest weakness. </p>
</div>
<div class='slide-image col-md-8'>
<!--
<ul class='imageList'>
<li><a href='#'><img src="images/jog.jpg" /></a></li>
<li><a href='#'><img src="images/health.png" /></a></li>
<li><a href='#'><img src="images/motivated.jpg" /></a></li>
<li><a href='#'><img src='images/possible.jpg' /></a></li>
</ul> -->
</div>
</div>
</div>
</div>
<div class='slide' id='slide3'>
<div class='container'>
<div class='row'>
<div class='slide-copy col-xs-5'>
<h1>Food Delight</h1>
<p>We have all been there before!! Food is the best type of comfort. Eating healthy is great but nothing can satisfied your soul more than your favorite rarities.</p>
<!--<img src="images/sushi.jpg"/>-->
</div>
</div>
</div>
</div>
<div class='slide' id='slide4'>
<div class='container'>
<div class='row'>
<div class='slide-copy col-xs-5'>
<h1>Videos</h1>
<p>Movies, TV shows and online video play such a huge role in our culture. Learning, Entertainment, Visual Satisfaction etc.</p>
<!--<iframe class='vid' width="750" height="400" src="https://www.youtube.com/embed/sGbxmsDFVnE" frameborder="0" allowfullscreen></iframe> -->
</div>
</div>
</div>
</div>
</div>
<div class='slider-nav'>
<ul class='slider-dot'>
<li class='dot dot1 active-dot'>•</li>
<li class='dot dot2'>•</li>
<li class='dot dot3'>•</li>
<li class='dot dot4'>•</li>
</ul>
</div>
Please see it's working here [1]: https://jsfiddle.net/e1aar5hz/11/
$(function() {
var pull = $('#pull');
var menu = $('nav ul');
menu.hide();
pull.show()
$(pull).on('click', function(e) {
e.preventDefault();
menu.slideToggle();
});
$(window).resize(function(){
var w = $(window).width();
if(w > 320 && menu.is(':hidden')) {
menu.removeAttr('style');
}
});
});
You code works just as it should. You target a link with id="pull" to toggle the menu on and off. The problem is, on your CSS, you hide that #pull link when you add this:
a#pull {
display: none;
}
So the button we need to click to toggle the menu is not there.
Just remove that CSS and you will see the "Menu" button and that the script is working fine.
If this is not the problem, please elaborate on what you are expecting to happen with the code you have here.
i recreated your code and is working just fine the only error i corrected was on displayTime function
function displayTime () {
var now = new Date();
var elt = $("#clock").text(now.toLocaleTimeString());
setTimeout (displayTime, 1000);
};
here is a demo http://plnkr.co/edit/6qNQMIQT4EhtqrlzUtGb?p=preview

Categories

Resources