For example current is https://academy/en/events/
If the page is following to the events page for example is https://academy/en/event/private/
how can I adjust the code to make when the page is (private) also make the events link has a active class
const current = location.href;
const menuItem = document.querySelectorAll(".collapse .navbar .nav a");
const menuLength = menuItem.length;
for (let i = 0; i < menuLength; i++) {
if (menuItem[i].href === current) {
menuItem[i].className = "active";
}
}
Related
I got 3 accordions in a Shopify product page out of which I intend to keep the first one expanded by default on page load. Once the page loaded, clicking other accordions should close all previously opened ones. I want to do it only with pure JavaScript(no libraries like jQuery) or CSS. My code below just ensures the first accordion is shown expanded. Could you please help correct my code after having a look at the accordions in the page https://wv3yau73hiyf9fhv-458195004.shopifypreview.com?
window.onload = function() {
var accItem = document.getElementsByClassName('accordion__item');
// Keep the first accordion open by default.
for (i = 0; i < accItem.length; i++) {
console.log("Within first for loop");
accItem[0].click();
accItem[i].addEventListener('click', toggleItem, false);
}
function toggleItem() {
var itemClass = this.parentNode.className;
for (i = 0; i < accItem.length; i++) {
console.log("Within second for loop");
accItem[i].className = 'accordion__item close';
}
if (itemClass == 'accordion__item close') {
this.parentNode.className = 'accordion__item open';
}
}
};
Using the browser's console on the page, I used the following to open the first accordion:
let allAccordions = document.querySelectorAll(".accordion__item");
allAccordions[0].click();
Yes, a loop is possible too:
for (var i = 0; i < allAccordions.length; i++) {
if (i == 0) {
allAccordions[i].click();
break; // only the first, can stop looping.
}
}
Finally, the solution is below:
// Keep the first accordion open by default.
let allAccordions = document.querySelectorAll(".accordion__item");
if (allAccordions.length > 0) {
allAccordions[0].querySelector("input[type=radio]").checked = true;
}
// Capture click event for the accordions
allAccordions.forEach(element => {
element.addEventListener('click', function() {
let radioBtn = this.querySelector("input[type=radio]");
let clickedRadioName = radioBtn.getAttribute("name");
allAccordions.forEach(element => {
let elementRadioBtn = element.querySelector("input[type=radio]");
let elementRadioName = elementRadioBtn.getAttribute("name");
if ((elementRadioName != clickedRadioName) && elementRadioBtn.checked) {
element.querySelector("input[type=radio]").checked = false;
}
});
});
});
I am trying to build a small program which you enter data into using input fields to build a set of unordered lists containing list items.
I have a checkbox of which that when it is checked, i would like it to display the entire unordered list that contains that bit of text, in this case, atlanta. I would like the rest of the unordered lists which do not contain this text to be set to display: none;
The for loop is the issue, though I have been playing around all day and cannot behave as I would like.
This is the code in question I believe:
checkboxInput.addEventListener('change', (e) => {
const isChecked = e.target.checked;
let ulList = document.getElementsByTagName('ul');
let liList = document.getElementsByTagName('li');
let locationList = document.getElementsByClassName('location');
if (isChecked) {
for (let i = 0; i < ulList.length; i += 1) {
for (let j = 0; j < liList.length; j += 1) {
let ul = ulList[i];
let li = liList[i];
if (li.textContent == 'atlanta') {
ul.style.display = '';
} else {
ul.style.display = 'none';
}
}
}
}
});
Please see a jsFiddle link here.
Any help much appreciated.
A couple of the variables I declared were unnecessary in this piece of code.
The liList variable was replaced with ulList.children.
The second for loop wasn't necessary either.
Here is the eventListener changed to achieve the functionality I required.
checkboxInput.addEventListener('change', (e) => {
const isChecked = e.target.checked;
let ulList = document.getElementsByTagName('ul');
if (isChecked) {
for (let i = 0; i < ulList.length; i += 1) {
let ul = ulList[i];
let liList = ul.children;
let li = liList[1];
if (li.textContent == 'atlanta') {
ul.style.display = 'block';
} else {
ul.style.display = 'none';
}
}
}
});
Thanks to Kris from Treehouse for the answer to this problem.
I created this function to handle the toggle for my mobile nav.
const mobileNav = document.getElementById('mobile-nav');
let tabs = document.getElementsByClassName('nav_tabs');
//nav toggle control
mobileNav.onclick = (event) => {
event.preventDefault();
for(let i = 0; i < tabs.length; i++) {
if(tabs[i].style.display === "block"){
tabs[i].style.display = "none";
} else {
tabs[i].style.display = "block";
}
}
};
It's working on great on mobile. The problem is when I resize, the toggle is still set to display none and the toggled menu options are not visible. I have tried using this JS Media Query to reset the display block based on a min-width of 786px but it is not reseting the menu.
// media query event handler
if (matchMedia) {
const dsktp = window.matchMedia("(min-width: 768px)");
dsktp.addListener(WidthChange);
WidthChange(dsktp);
}
function WidthChange(elem) {
for(let i = 0; i < elem.length; i++) {
tabs[i].style.display = "block";
}
}
Here's a codepen of the problem.
Your code does not work because of this code (pay attention to the comments):
if (matchMedia) {
const dsktp = window.matchMedia("(min-width: 768px)");
dsktp.addListener(WidthChange); // <-- add function as handler
WidthChange(dsktp);
}
function WidthChange(elem) { // elem argument it is not the dom elements here
for(let i = 0; i < elem.length; i++) {
tabs[i].style.display = "block";
}
}
So you should rewrite your code this way:
if (matchMedia) {
const dsktp = window.matchMedia("(min-width: 768px)");
dsktp.addListener(WidthChange);
WidthChange(dsktp);
}
function WidthChange(mediaQueryEvent) {
for(let i = 0; i < tabs.length; i++) {
tabs[i].style.display = mediaQueryEvent.matches ? "block" : "none";
}
}
Check my fork of your pen.
I have the following script, from my previous question. I tried running it but it won't work. There isn't any console message as well. It does conflict with something in console called lstr.js (I think it is chrome related), the code works fine in jsfiddle but not on my machine.
var links = document.getElementsByClassName('link'), // add a class to the links and get them all
contentDivs = document.getElementsByClassName('content'); // same with the content blocks
for (i = 0; i < links.length; i++) { // loop through the links to add the event listeners
var link = links[i];
// add event listener
link.addEventListener('click', function(event) {
// reset color and hide content:
for (a = 0; a < links.length; a++) {
// number of links should match number of content
links[a].style.backgroundColor = 'magenta';
contentDivs[a].style.display = 'none';
}
// set colour of clicked
event.target.style.backgroundColor = 'grey';
// show clicked content
document.getElementById(event.target.getAttribute("href").substring(1)).style.display = 'block';
})
}
Wrap that in a function and then do
document.addEventListener('DOMContentLoaded', function() {
nameOfYourFunction();
});
So in the end, your could would look like
function attachEvents() {
var links = document.getElementsByClassName('link'); // add a class to the links and get them all
var contentDivs = document.getElementsByClassName('content'); // same with the content blocks
for (i = 0; i < links.length; i++) { // loop through the links to add the event listeners
var link = links[i];
// add event listener
link.addEventListener('click', function(event) {
// reset color and hide content:
for (a = 0; a < links.length; a++) {
// number of links should match number of content
links[a].style.backgroundColor = 'magenta';
contentDivs[a].style.display = 'none';
}
// set colour of clicked
event.target.style.backgroundColor = 'grey';
// show clicked content
document.getElementById(event.target.getAttribute("href").substring(1)).style.display = 'block';
});
}
}
document.addEventListener('DOMContentLoaded', function() {
attachEvents();
}
The code is OK except you ought to check if links.length === contentDivs.length
I currently have it so my titles slide in when the link is clicked.
How do I make it so that (when the link is clicked) the current title will slide out before the new one slides in?
This is the clicked event I have been using. It might be all wonky, I have been adding different things to it to try and get it to work.
// list of sections. the first section contains only the h1.
var sections = document.querySelectorAll("section");
function hideSections() {
for (var i = 0; i < sections.length; i++) {
sections[i].className = "hidden";
}
}
// list of links in the nav.
var links = document.querySelector("nav").querySelectorAll("a");
// add listeners to those links
for (var i = 0; i < links.length; i++) {
links[i].addEventListener("click", clicked);
}
function clicked(event) {
var target = document.querySelector('h2');
target.className = "slideout";
event.preventDefault();
hideSections();
var current = event.target.hash;
// "show" appropriate selection, based on id from link
document.querySelector(current).className = "";
// modify URL to reflect current location
location.hash = current;
target.addEventListener("animationend", newfile);
function newfile() {
target.removeEventListener("animationend", newfile);
}
target.addEventListener("animationstart", newfile);
}
// when page loads...
hideSections();
if (location.hash == "") {
sections[0].className = "";
} else {
document.querySelector(location.hash).className = "";
}
https://jsfiddle.net/yk7w2zt2/
Here is my full code.
You need you delay showing the next section until after the h2 has slid off the screen.
See JSFiddle using setTimeout():
https://jsfiddle.net/w9uypaae/