Issue with tab links disappearing when clicking elsewhere on the page - javascript

I'm new to Javascript and I'm having problem with the tab links set on my webpage.
The links cycle trough and display the appropriate content, however, when it comes to adding the styling of the active button, on loading the page the underline shows correctly and clicking elsewhere keeps it in place, but if I click on the other links and then click elsewhere the styling disappear.
The full code is here https://codepen.io/Rei89/pen/VwBrJEr
this is the piece I'm having trouble with:
const tabsContainer = document.getElementById("links");
const tabs = tabsContainer.getElementsByClassName("tablinks");
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener("click", () => {
let current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
};

You can use other methods such as remove and add :D
const tabsContainer = document.getElementById("links");
const tabs = tabsContainer.getElementsByClassName("tablinks");
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener("click", () => {
let current = document.getElementsByClassName("active")[0];
current.classList.remove("active");
tabs[i].classList.add("active");
});
};

You can add and remove classes using javascript like this. Before adding 'active' class, remove that from all 'tablinks'.
const tabsContainer = document.getElementById("links");
const tabs = tabsContainer.getElementsByClassName("tablinks");
// Loop through the buttons and add the active class to the current/clicked button
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener("click", () => {
removeClasses();
tabs[i].classList.add("active");
});
};
var els = document.querySelectorAll('.tablinks')
function removeClasses() {
for (var i = 0; i < els.length; i++) {
els[i].classList.remove('active')
}
}

Related

How to run a function on click and url change JQuery

Right now I'm trying to use JQuery to set text at the end of a products name for a website. But the issue is right now it's set up to run when the document is ready.
So for some reason when switching pages it's not refreshing the page just adding to the url and changing products which is fine, but my code doesn't work for the other pages.
Example:
https://www.example.com/category
to
https://www.example.com/category/?sort=featured&page=2
I know that my code isn't as efficient as it could be, and there's reused code. But right now I'm just trying to get it to work before cleaning it up further. I couldn't really find anything online that really worked other than doing a location.reload() when the page nav was pressed. Unfortunately that ended up creating an infinite loop on the page.
I'm not sure if I'm just not thinking of the correct way to go about this or if my code isn't working as intended. I don't get any errors in the console either.
What I've tried:
Creating a selector for the page navigation so when clicked it will run the same code again.
Tried using a listener to listen for the clicks.
Tried checking if the url has changed.
Tried to refresh the page after clicking on page navigation along with using a timeout to wait for the page to change then refresh.
Code:
script1 - Handles adding text to product titles
$(document).ready(function() {
var multiTitle = $(".card-title");
var prodTitle = $(".productView-title");
var array = [list of titles];
if (multiTitle.length > 0) {
for (var i = 0; i < multiTitle.length; i++) {
for (var j = 0; j < array.length; j++) {
if (multiTitle[i].innerText == array[j]) {
var text = document.createElement('span');
text.innerHTML = "<span>text</span></br>";
multiTitle[i].prepend(text);
}
}
}
}
if (prodTitle.length > 0) {
for (var j = 0; j < array.length; j++) {
if (prodTitle[0].innerText == array[j]) {
var text = document.createElement('span');
text.innerHTML = "<span>text</span></br>";
prodTitle[0].append(text);
}
}
}
});
script2 - should re-add text after titles when pages change
$(".pagination-list").click(function() {
$(window).bind('hashchange', function() {
var multiTitle = $(".card-title");\
var prodTitle = $(".productView-title");
var array = [list of titles];
if (multiTitle.length > 0) {
for (var i = 0; i < multiTitle.length; i++) {
for (var j = 0; j < array.length; j++) {
if (multiTitle[i].innerText == array[j]) {
var text = document.createElement('span');
text.innerHTML = "<span>text</span></br>";
multiTitle[i].prepend(text);
}
}
}
}
if (prodTitle.length > 0) {
for (var j = 0; j < array.length; j++) {
if (prodTitle[0].innerText == array[j]) {
var text = document.createElement('span');
text.innerHTML = "<span>text</span></br>";
prodTitle[0].append(text);
}
}
}
});
});

Javascript passing info from one function to another

I've created a JS function that hides a certain amount of breadcrumbs if there are too many. They are replaced by a button (ellipsis), when you click the button the hidden breadcrumbs are revealed.
The Problem: I loop through the breadcrumbs to see if there are enough to hide. If there are I hide them. But I can't figure out how to then call the code to create the button. If I call the button code in the loop I get more than 1 button generated.
Right now the button will always appear whether there are enough breadcrumbs to hide or not.
In my mind, I would have the for loop with the if statement return true to what would then be the button function. But I can't figure out how to do this. Please offer any pointers for restructuring this code if you can.
Here's a Codepen: https://codepen.io/sibarad/pen/GRvpEbp
Basic HTML:
<nav aria-label="breadcrumb">
<ol class="c-breadcrumb mb-7 md:mb-8">
<li class="c-breadcrumb-item">
Breadcrumb 1
</li>
<li class="c-breadcrumb-item">
Breadcrumb 2
</li>
<li class="c-breadcrumb-item">
Longer Breadcrumb Name 03
</li>
</ol>
</nav>
Javascript:
function breadcrumb() {
// Target specific breadcrumbs, not 1st or last 2
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item:nth-child(1n+2):nth-last-child(n+3)');
// Loop through select breadcrumbs, if length is greater than x hide them.
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
if(hiddenbreadcrumb.length >= 3) {
hiddenbreadcrumb[i].style.display = "none";
}
}
// This would be the button function, but I don't know how to engage this only if the if statement above was met.
let li = document.createElement('li');
li.className = 'c-breadcrumb-item';
let ellipbutton = document.createElement('button');
ellipbutton.type = 'button';
ellipbutton.innerHTML = '...';
ellipbutton.className = 'c-breadcrumb_btn u-btn-clear';
ellipbutton.onclick = function() {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
li.appendChild(ellipbutton);
let container = document.querySelector('.c-breadcrumb-item:first-child');
container.insertAdjacentElement("afterend", li);
}
breadcrumb();
We can refactor your code slightly to achieve this - the if statement which checks whether there are more than 3 breadcrumbs doesn't need to be inside the for loop - it's redundant to keep checking the same value multiple times.
If we move that outside the loop then it can
a) prevent unnecessary looping when there aren't enough breadcrumbs, and
b) wrap around the button creation code as well, which should solve your problem.
For example:
if (hiddenbreadcrumb.length >= 3) {
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
let li = document.createElement('li');
li.className = 'c-breadcrumb-item';
let ellipbutton = document.createElement('button');
ellipbutton.type = 'button';
ellipbutton.innerHTML = '...';
ellipbutton.className = 'c-breadcrumb_btn u-btn-clear';
ellipbutton.onclick = function() {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
let container = document.querySelector('.c-breadcrumb-item:first-child');
container.insertAdjacentElement("afterend", li);
}
It looks like some small initialization issues. This should correct it:
Change this:
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item:nth-child(1n+2):nth-last-child(n+3)');
// Loop through select breadcrumbs, if length is greater than x hide them.
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
if(hiddenbreadcrumb.length >= 3) {
hiddenbreadcrumb[i].style.display = "none";
}
}
to this:
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item');
if(hiddenbreadcrumb.length < 3)
return
for (var i = 1; i < hiddenbreadcrumb.length - 1; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
Try this... it allows 3 li items as item1 ... item2ndLast, itemLast
(function () {
"use strict";
function breadcrumb() {
let hiddenbreadcrumb = document.querySelectorAll(".c-breadcrumb-item:nth-child(1n+2)");
if (hiddenbreadcrumb.length <= 3) return;
for (var i = 1; i < hiddenbreadcrumb.length - 1; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
let li = document.createElement("li");
li.className = "c-breadcrumb-item";
let ellipbutton = document.createElement("button");
ellipbutton.type = "button";
ellipbutton.innerHTML = "...";
ellipbutton.className = "c-breadcrumb_btn u-btn-clear";
ellipbutton.onclick = function () {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
li.appendChild(ellipbutton);
let container = document.querySelector(".c-breadcrumb-item:first-child");
container.insertAdjacentElement("afterend", li);
}
breadcrumb();
})();

Hover style in css is disabled by javascript codes, how to use them?

there is some images with grayscale(1) by default and when you hover on images it should change to grayscale(0), all of this is on css file. but i want when i click on it or when i hover on it, on both situations the image gets grayscale(0) but the hover effect doesn't work. i tried to put the code for grayscale(0) on an addEventListener in another function but it didn't work.
update:
i added codpen link and one line of code.
as you can see from the beginning left person is coloured because i'm showing their info. i want that when i hover on other persons, they get coloured theme while the person that their info is up is still coloured.
link
showInfo(0);
function showInfo(person) {
var img, info, names;
names = document.querySelectorAll('.box h2');
for (let i = 0; i < names.length; i++) {
names[i].style.display = 'none';
}
names[person].style.display = 'block';
info = document.querySelectorAll('.info p');
for (let i = 0; i < info.length; i++) {
info[i].style.display = 'none';
}
info[person].style.display = 'block';
img = document.querySelectorAll('.images img');
for (let i = 0; i < img.length; i++) {
img[i].style.filter= 'grayscale(1)';
}
img[person].style.filter= 'grayscale(0)';
}
I have updated your showInfo function:
function showInfo(person) {
var img, info, names;
names = document.querySelectorAll('.box h2');
for (let i = 0; i < names.length; i++) {
names[i].style.display = 'none';
}
names[person].style.display = 'block';
info = document.querySelectorAll('.info p');
for (let i = 0; i < info.length; i++) {
info[i].style.display = 'none';
}
info[person].style.display = 'block';
img = document.querySelectorAll('.images img');
for (let i = 0; i < img.length; i++) {
img[i].style.filter= '';
}
img[person].style.filter= 'grayscale(0)';
}
showInfo(0);
The change is very small and that gets you to the required behaviour:
for (let i = 0; i < img.length; i++) {
img[i].style.filter= '';
}

Link Divblock with dynamic link

i'd like to link a divblock with the current position within the for-loop
Problem: all DivBlock get the link with the last position of the loop
my code is like this:
for (var i = 1; i <= kundenAnzahl; i++) {
var block = document.createElement("div");
block.id = i.toString();
document.getElementById(i.toString()).addEventListener('click', function() {
location.href = 'server.html?kunde='+i
}, true);
change var to let because -> https://wesbos.com/for-of-es6/
and you can assign event listeners directly to new created div element, look this code
for (let i = 0; i < 5; i++) {
var block = document.createElement('div');
block.addEventListener('click', function() {
location.href = 'server.html?kunde='+i;
}, true);
document.body.append(block);
}

Access elements in ul list

I have the following list hierarchy:
<ul id="ulid">
<li><a><div class="mydiv">content</div></a></li>
<li><a><div class="mydiv">content</div></a></li>
...
</ul>
I want to add some css rules to the div and this is what i've tried so far:
var myul = document.getElementById("ulid");
var myli = myul.getElementsByTagName("li");
for(var i = 0; i < myli.length; i++) {
//myli[i].parentNode.style.display = "none"; // that works
var links = myli[i].getElementsByTagName("a");
for(var ii = 0; ii < links.length; ii++) {
links[ii].parentNode.style.display = "none"; // doesnt work
}
}
I can hide the li items but cant do the same for a So i cant reach the div. What am i doing wrong here?
EDIT: getElementsByClassName seems not working in greasemonkey scripts as it simply works in Emmanuel N's fiddle.
Your code seems to work. Check out this Fiddle
var myul = document.getElementById("ulid");
var myli = myul.getElementsByTagName("li");
for(var i = 0; i < myli.length; i++)
{
var links = myli[i].getElementsByTagName("a");
for(var ii = 0; ii < links.length; ii++)
{
links[ii].parentNode.style.display = "none";
}
}
Your code actually does work, but I don't think it does what you're intending it to do. The last line: links[ii].parentNode.style.display = "none" will actually hide the parent node of the a tag (i.e. the li) tag, rather than the div. parentNode will go one level UP, not down.
Instead of trying to get myli[i].getElementsByTagName("a") and then working down to the div, why not myli[i].getElementsByTagName("div"), and then simply do:
var myul = document.getElementById("ulid");
var myli = myul.getElementsByTagName("li");
for(var i = 0; i < myli.length; i++) {
//myli[i].parentNode.style.display = "none"; // that works
var links = myli[i].getElementsByTagName("div");
for(var ii = 0; ii < links.length; ii++) {
links[ii].style.display = "none";
}
}
Of course, there are many more efficient ways to do it. You already have classnames on the divs, so
document.getElementsByClassName("mydiv");
would work just as well.
Or, if you use jQuery, you can do the same thing without having to iterate explicitly:
$("div.mydiv").css(etc.); // style this however you want
If you aren't opposed to using jQuery, the following would hide your divs for you.
$(document).ready(function () {
var myDivs = $('div.mydiv');
for(var eachDiv in myDivs) {
$(eachDiv).hide();
}
});

Categories

Resources