Hi sorry in advance if this has already been asked but I can't find the answer.
I have a set of links that trigger certain ids to show onclick, it works but the one link is suppose to trigger 2 ids to show. My javascript knowledge is not great. Thanks for any help.
Here is my codepen https://codepen.io/louise-fourie/pen/abVdwyZ
<li>
Fitness & Wellness
</li>
<li>
Business
</li>
<li>
Arts & Entertainment
</li>
</ul>
<div class="articles">
<div id="el-57d5b6f71db32029">fitness</div>
<div id="el-e881a23a64890108">business</div>
<div id="el-65ebd7b2380005a1">art</div>
</div>
<script>
var divs = ["el-57d5b6f71db32029", "el-e881a23a64890108", "el-65ebd7b2380005a1"];
var visibleId = null;
function show(id) {
for(i = 0; i < divs.length; i++) {
if(visibleId !== id) {
visibleId = id;
}
}
hide();
}
function hide() {
var div, i, id;
for(i = 0; i < divs.length; i++) {
id = divs[i];
div = document.getElementById(id);
if(visibleId === id) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
There is something fishy with your show-hide logic.
Check out my suggestion below, where you can pass an array of IDs, which you want to show. All other elements will be hidden.
function onClick(elements) {
document.querySelectorAll('.articles div').forEach(articleDiv => articleDiv.style.display = 'none');
elements.forEach(element => {
const domEl = document.querySelector('#' + element)
domEl.style.display = 'block';
})
}
<ul>
<li>
Fitness & Wellness
</li>
<li>
Business
</li>
<li>
Arts & Entertainment
</li>
</ul>
<div class="articles">
<div id="fitness">fitness</div>
<div id="business">business</div>
<div id="art">art</div>
</div>
<script>
</script>
Your function seems to be running, but every time you receive an ID in your function, you hide everything else with the "hide" function, so in the end, the last ID sent, is the only one that will show, try this:
Call the function once, but pass the IDs as one string separated by commas
Business
Then change your "show" function like this:
function show(ids) {
let idArr = ids.split(",");
divs.forEach( x => {
div = document.getElementById(x);
div.style.display = (idArr.includes(x) ? "block" : "none");
});
}
What this does, is that it will create an array of IDs based on the parameter you send, and for each item it will check if the ID was sent and show/hide it.
Please let me know if this helps or if you need more details.
EDIT: Formatting in the JavaScript code and simplifying it. Please also note that here I am not validating if the an element with the ID exists, it is only to show you how it can work. It will need additional validations
You can try it
<ul>
<li>
Fitness & Wellness
</li>
<li>
Business
</li>
<li>
Arts & Entertainment
</li>
</ul>
<div class="articles">
<div id="el-57d5b6f71db32029" style="display:none;">fitness</div>
<div id="el-e881a23a64890108" style="display:none;">business</div>
<div id="el-65ebd7b2380005a1" style="display:none;">art</div>
</div>
<script>
document.querySelectorAll('.article-btn').forEach(item => {
item.addEventListener('click', event => {
show((item.getAttribute('data-id')).split(";"));
})
})
const show = (id) => {
document.querySelectorAll('.articles>div').forEach(item => {
if(id.includes(item.getAttribute('id'))){
item.style["display"] = "block";
}else{
item.style["display"] = "none";
}
});
}
</script>
Inline JavaScript is generally discouraged these days, so here's a solution that removes that dependency. It puts the ids of the list items into the dataset instead. You can then create an array from that dataset, iterate over the articles, and if the id is included in the array of ids either hide or show it.
// Cache the list and the articles
const ul = document.querySelector('ul');
const articles = document.querySelectorAll('.articles div');
// Add an event listener to the list
ul.addEventListener('click', handleClick, false);
function handleClick(e) {
// Get the node name and the dataset
// from the element that was clicked
const { nodeName, dataset } = e.target;
// Check that it was an anchor
if (nodeName === 'A') {
// Get an array of ids from the dataset
const ids = dataset
.ids.split(',')
.map(id => id.trim());
// Hide all the articles
articles.forEach(article => {
article.classList.add('hide');
});
// Show the articles where the id is in
// the list of ids
articles.forEach(div => {
if (ids.includes(div.id)) {
div.classList.remove('hide');
}
});
}
}
.hide { display: none; }
ul li:hover { cursor: pointer; color: red; }
<ul>
<li>
<a data-ids="el-57d5b6f71db32029">Fitness & Wellness</a>
</li>
<li>
<a data-ids="el-57d5b6f71db32029, el-e881a23a64890108">Business</a>
</li>
<li>
<a data-ids= "el-65ebd7b2380005a1">Arts & Entertainment</a>
</li>
</ul>
<div class="articles">
<div id="el-57d5b6f71db32029" class="hide">fitness</div>
<div id="el-e881a23a64890108" class="hide">business</div>
<div id="el-65ebd7b2380005a1" class="hide">art</div>
</div>
Related
I would like to display creating product in admin section sub categories in tree only when selected else closed in woocommerce product categoreis. How can I achieve this ? Presently it appears like this. Tried css but didn't work.
<li id="tire_sizes-52"><label class="radiall"><input value="52" type="checkbox" name="tax_input[tire_sizes][]" id="in-tire_sizes-52"> 145</label><ul class="children">
<li id="tire_sizes-62"><label class="radiall"><input value="62" type="checkbox" name="tax_input[tire_sizes][]" id="in-tire_sizes-62"> 65</label> <ul class="children">
<li id="tire_sizes-87"><label class="radiall"><input value="87" type="checkbox" name="tax_input[tire_sizes][]" id="in-tire_sizes-87"> 15</label></li>
</ul>
</li>
</ul>
</li>
I want it closed and open only if selected
// if a checkbox has a child, add a css class="has-children"
// select them
const parents = document.querySelectorAll('.has-children')
const caches = parents.map(() => ([]))
function clear(parent) {
const id = parent.getAttribute('id');
const ul = parent.querySelector('.children');
ul.css.display = 'none'; // hide from the DOM
// you may also need to remove it from the DOM
/*
children = [];
while (parent.firstChild) {
const firstChild = parent.firstChild
parent.removeChild(firstChild)
caches[id].push(firstChild);
}*/
}
// inital setup
parents.forEach(function (parent) {
const id = parent.getAttribute('id');
clear(parent);
// setup listen for changes to parents
parent.addEventListener('change', function() {
let child;
if (child = parent.querySelector('children')) {
if (child.css.display === 'block') {
clear(parent)
} else {
//caches[this.getAttribute('id')].forEach(c =>
// this.appendChild(c)
delete caches[this.getAttribute('id')]
const ul = parent.querySelector('.children');
ul.css.display = 'block'; // show from bom
}
});
})
something like this. Checkout jquery it may be easier
If this is right, please give me points, i'm a nooob
I haven't executed this code , so it will need your attentions. but that is the essance of it. As I say. look into jquery. This can be accomplished in 3 lines of code.
I want to add a class to an element that shares the same data attribute value using vanilla JS. The class is added on mouseenter.
My current setup only applies the class on hover to the first element and ignores the rest.
let section = document.querySelector('.section');
let links = document.querySelectorAll('.links a');
let triggerVal;
let linkedVal;
links.forEach(function(link, index) {
link.addEventListener('mouseenter', function() {
triggerVal = this.dataset.triggerValue;
linkedVal = section.dataset.linkedValue;
if (linkedVal === triggerVal) {
section.classList.add('is-active');
} else {
section.classList.remove('is-active');
}
});
});
<ul class="links">
<li>
<a data-trigger-value="red" href="#">Red</a>
</li>
<li>
<a data-trigger-value="yellow" href="#">Yellow</a>
</li>
<li>
<a data-trigger-value="blue" href="#">Blue</a>
</li>
</ul>
<div class="wrapper">
<div class="section" data-linked-value="red">
<h2>Red</h2>
</div>
<div class="section" data-linked-value="yellow">
<h2>Yellow</h2>
</div>
<div class="section" data-linked-value="blue">
<h2>Blue</h2>
</div>
</div>
Here's a Codepen: https://codepen.io/abbasarezoo/pen/7378e190ed6ad117faca968b634520b0
I've got a feeling it's to do with the .section element but I've tried a few things and nothing seems to give me what I need.
Any suggestions as to what I need to do to get the rest of the elements working?
You need to change two things:
First, get all sections:
const section = document.querySelectorAll('.section');
Then, inside your handler, you need to iterate over the NodeList returned by querySelectorAll():
for (const section of sections) {
linkedVal = section.dataset.linkedValue;
if (linkedVal === triggerVal) {
section.classList.add('is-active');
} else {
section.classList.remove('is-active');
}
}
This is your new JS:
const sections = document.querySelectorAll('.section');
const links = document.querySelectorAll('.links a');
let triggerVal;
let linkedVal;
links.forEach(function(link, index){
link.addEventListener('mouseenter', (e) => {
triggerVal = e.target.dataset.triggerValue;
for (const section of sections) {
linkedVal = section.dataset.linkedValue;
if (linkedVal === triggerVal) {
section.classList.add('is-active');
} else {
section.classList.remove('is-active');
}
}
});
});
You need to use document.querySelectorAll for sections and then forEach. And use toggle instead of add/remove for this case. https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
let sections = document.querySelectorAll('.section');
let links = document.querySelectorAll('.links a');
let triggerVal;
let linkedVal;
links.forEach(function(link, index) {
link.addEventListener('mouseenter', function() {
triggerVal = this.dataset.triggerValue;
sections.forEach(
section => section.classList.toggle(
'is-active',
section.dataset.linkedValue === triggerValue
)
);
});
});
Is it possible to change a certain on hover over another certain item.
For example:
<li>
test
</li>
JS
var list = document.getElementById('li');
var link = document.getElementById('a');
list.onmouseover = function() {
link.style.color = "#8080ff";
}
If i hover over the li item I want the text inside the a tag to change, but this code is not working.
I cant use css or jquery library.
http://jsfiddle.net/Nt8Pq/40/
Your code looks for elements with ids and you have not ids. You would need to select them by the tag name and loop over the collection. And than you would need to find the anchor that is inside of the collection.
var menu = document.getElementById("menu");
var lis = menu.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
var li = lis[i];
li.addEventListener("mouseover", function() {
this.getElementsByTagName("a")[0].style.color = "#8080ff";
});
li.addEventListener("mouseout", function() {
this.getElementsByTagName("a")[0].style.color = "#000000";
});
}
<ul id="menu">
<li>
test
</li>
<li>
test
</li>
<li>
test
</li>
</ul>
In the end this is a lot of code to implement
ul li:hover a {
color : "#8080ff";
}
SO you could just inject a CSS rule if you are not able to actually add styles to the page...
var sheet = window.document.styleSheets[0];
sheet.insertRule('#menu li:hover a { color: #8080ff; }', sheet.cssRules.length);
<ul id="menu">
<li>
test
</li>
<li>
test
</li>
<li>
test
</li>
</ul>
This can be done with some simple HTML event attributes and JavaScript.
<li>
test
</li>
HTML Event Attributes
If you want to do it with JS, here is the answer. But like said before, you shouldn't do it this way:
<li id="list">
<a id="link" href="#">test</a>
</li>
var list = document.getElementById('list');
var link = document.getElementById('link');
http://jsfiddle.net/Nt8Pq/45/
Assuming you can not modify the CSS or the source of the web page, and you are stuck only with a single javascript file in which you wish to modify some features of a web page, then this approach will work:
One caveat is you have to use of an index in document.getElementsByTagName('li') which returns an array. If you always need the first element for example, you can hard code this index as zero. Otherwise, you need to iterate over the collection looking for the one you wish to change.
Finally, you can modify the style of the firstChildElement after you find the list item you want.
var li = document.getElementsByTagName('li')[0];
li.onmouseover = function() {
li.firstElementChild.style.color = "#F00"; // red
}
li.onmouseout = function() {
li.firstElementChild.style.color = "#000"; // black
};
<li>
Mouse over me.
</li>
var nodesArray = document.getElementById('myID').getElementsByTagName('a');
for (var i = 0; i < nodesArray.length; i++) {
nodesArray[i].style.color = 'red';
}
May be you will find your solution in this link:-https://ubuntuforums.org/showthread.php?t=1692280
I have a menu that contains 3 items. How can I change that the text to what it's selected from the menu?
HTML
<div id="dropdown-container">
<div id="index-tab" onclick="toggleMenu()">1</div>
<ul id="dropdown">
<li ><span class="current-browse">1</span>
<ul class="dropdown-items">
<li class="dropdown-item">2</li>
<li class="dropdown-item"">3</li>
</ul>
</li>
</ul>
</div>
JavaScript
function toggleMenu() {
var dropDown = document.getElementById('dropdown');
if(dropdown.style.display == "block") {
dropdown.style.display = "none";
} else {
dropdown.style.display = "block";
}
}
For example the menu currently showing:
1
1
2
3
If selected 2, it will show:
2
2
1
3
If selected 3 it will show :
3
3
1
2
Are you wanting to set the text of index-tab or the text of the current-browse span? Either way you need some click handlers on the li items that gets the element with the id or class of whichever one you want to set (Will need to get the anchor child of the index-tab div if it is used). Then replace the text element of the anchor or span. jQuery will make it a bit easier, but can be done either way. The jQuery example given will need to get the anchor child to then set text, and doing it when showing the menu is not what you want since no item is clicked yet.
Added toggleSelection() function:
event.preventDefault(); used to prevent links default action which is jumping to a location.
selectedItem references event.target (i.e. the element that was actually clicked), which is either the one of the .dropdown-items.
There's multiple exchanges between elements based on the .textContent of the selectedItem. At this point, #current-browse, and #index-tab a (the link in #index-tab) have a new .textContent and selectedItem has the previous item number.
All of that will not happen until #dropdown is clicked on and the event.target is determined. this is possible by the eventListener:
dropDown.addEventListener('click', toggleSelection, false);
SNIPPET
function toggleMenu() {
var dropDown = document.getElementById('dropdown');
if (dropDown.style.display == "block") {
dropDown.style.display = "none";
} else {
dropDown.style.display = "block";
}
}
function toggleSelection(event) {
event.preventDefault();
var selectedItem = event.target;
var targetItem = selectedItem.textContent;
var currentItem = document.getElementById('current-browse');
var prevItem = currentItem.textContent;
var extLink = document.querySelector('#index-tab a');
currentItem.textContent = targetItem;
extLink.textContent = targetItem;
selectedItem.textContent = prevItem;
}
var dropDown = document.getElementById('dropdown');
dropDown.addEventListener('click', toggleSelection, false);
<div id="dropdown-container">
<div id="index-tab" onclick="toggleMenu()">1
</div>
<ul id="dropdown">
<li><span id="current-browse">1</span>
<ul class="dropdown-items">
<li class="dropdown-item">2
</li>
<li class="dropdown-item">3
</li>
</ul>
</li>
</ul>
</div>
REFERENCE
addEventListener vs. onclick
'this' and EventHandlers
you need to write the toggleMenu() in a way that it changes the text of index-tab based on the value of dropdown:
$("#index-tab").text($(".dropdown-item option:selected").text())
I have a bunch of links in my footer and I want to link to different headings on a page and create a click event so a associated paragraph changes from display: none to display: block.
Put another way: You see headings and a footer with links (like the demo). You click the footer links and the screen should jump to (link to) an associated h2 and display a previously hidden and associated p.
Here is what I have: I can display the paragraphs when I click on the headings directly (adapted from a stackoverflow post). I can link to the headings when I click on the links in the footer. But I need to display the associated paragraph and link to a heading (both) when I click the footer links.
Here is my markup so far:
<div class="service">
<h2 class="page services"><img class="img-bullet-services" src="websiteDot.png" alt="alt">service1</h2>
<p class="p-on-white service-desc p-hide" id="service1">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
</div>
</br>
<div class="service">
<h2 class="page services"><img class="img-bullet-services" src="websiteDot.png" alt="alt">service2</h2>
<p class="p-on-white service-desc p-hide" id="service2">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</p>
</div>
<div id="col4-footer" class="four-cols-footer four-cols">
<ul>
<li style="list-style: none;">
<h3><a class="a-bold" href="Services.php">Services</a></h3>
</li>
<li>service1
</li>
<li>seervice2
</li>
</ul>
</div>
css:
.p-hide {
display: none;
}
js:
var services = document.getElementsByClassName('service'),
servicedesc;
for (var i = 0; i < services.length; i++) {
services[i].addEventListener("click", function () {
servicedesc = this.getElementsByClassName('service-desc');
for (var j = 0; j < servicedesc.length; j++) {
servicedesc[j].classList.toggle('p-hide');
}
});
}
Demo:
http://jsfiddle.net/4GgRY/
I need the solution in vanilla JavaScript.
Hope this works
<html>
<head>
<title>internav</title>
<style type="text/css">
.hideclass{
display: none;
}
</style>
</head>
<body>
<div class="service" id="div1">
<h2 class="page services"><img class="img-bullet-services" src="websiteDot.png" alt="alt">service1</h2>
<p class="service-desc" id="service1">
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
</p>
</div>
</br>
<div class="service" id="div2">
<h2 class="page services"><img class="img-bullet-services" src="websiteDot.png" alt="alt">service2</h2>
<p class="service-desc" id="service2">
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
xxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>
</p>
</div>
<div id="col4-footer" class="four-cols-footer four-cols">
<ul>
<li style="list-style: none;">
<h3><a class="a-bold" href="Services.php">Services</a></h3>
</li>
<li>service1
</li>
<li>seervice2
</li>
</ul>
</div>
<script type="text/javascript">
function toggle (link) {
target = link.getAttribute("data-toggle");
servides = document.getElementsByClassName('service-desc');//.className += " hideclass";
for (var i = servides.length - 1; i >= 0; i--) {
//servides[i].className -= " hideclass";
servides[i].className = "service-desc hideclass";
};
document.getElementById(target).className = "service-desc";
}
</script>
</body>
</html>
Hello mountainclimber,
I hope this helps you out.
If I understand your question correctly, you wish to be able to navigate to the anchors within the page and at the same time un-hide a previously hidden (or other) tag.
To that end I took your original example and developed a new version. It may not be the very best version in the world, but I think it accomplishes what you asked.
The pertinent changes are as follows.
JS:
var useQuerySelector = false;
//Shim from jscheuer1 -- http://www.dynamicdrive.com/forums/showthread.php?68847-Why-getelementsbyclassname-not-working-IE
if (!document.getElementsByClassName)
{
document.getElementsByClassName = function (cn)
{
var rx = new RegExp("(?:^|\\s)" + cn+ "(?:$|\\s)");
var allT = document.getElementsByTagName("*"), allCN = [],ac="", i = 0, a;
while (a = allT[i=i+1])
{
ac=a.className;
if ( ac && ac.indexOf(cn) !==-1)
{
if(ac===cn)
{
allCN[allCN.length] = a; continue;
}
rx.test(ac) ? (allCN[allCN.length] = a) : 0;
}
}
return allCN;
}
}
//My own feature "sniffing"
try
{
document.getElementByClassName('');
}
catch(ex)
{
useQuerySelector = true;
}
function navigateToAnchor(anchorObject)
{
var anchorName = anchorObject.href.substring(anchorObject.href.lastIndexOf("#")+1, anchorObject.href.length)
var tagObj = document.getElementById(anchorName);
var hiddenElements = (!useQuerySelector?tagObj.parentElement.getElementsByClassName("p-hide"):tagObj.parentElement.querySelectorAll(".p-hide"));
toggleElements(hiddenElements, false);
}
function toggleElements(hiddenElements, bHide)
{
var objCurrElement = null;
for (i = 0; i < hiddenElements.length; i++)
{
objCurrElement = hiddenElements[i];
if (objCurrElement != null && objCurrElement != 'undefined')
{
if (bHide)
{
//Add the p-hide class.
objCurrElement.className += "p-hide";
}
else
{
//Remove the p-hide class.
objCurrElement.className = objCurrElement.className.replace(/p\-hide/,'');
}
}
}
}
Alternatively, using a syntax I have never used before you could do it this way
JS:
function toggleElements(hiddenElements, bHide)
{
var objCurrElement = null;
for (i = 0; i < hiddenElements.length; i++)
{
objCurrElement = hiddenElements[i];
tmpObj = objCurrElement;
if (objCurrElement != null && objCurrElement != 'undefined')
{
if (bHide)
{
//Add the p-hide class.
objCurrElement.classList.add("p-hide");
}
else
{
//Remove the p-hide class.
objCurrElement.classList.remove("p-hide");
}
}
}
}
HTML:
<li>Service 1</li>
<li>Service 2</li>
That's what I have :) I have tested it clean in the latest version of FireFox and Chrome as well as IE 8 and 9.
Please let me know if it helps!
I asked the initial question and I got a good answer from g-newa, but here is an alternative (really a modification of what g-newa posted). To make it work you have to move the service1 and service2 ids up into the div:
js:
var target, sericeDiv, pToDisplay
function toggle(link) {
target = link.getAttribute("data-toggle");
sericeDiv = document.getElementById(target)
pToDisplay = sericeDiv.getElementsByTagName('p')[0]
pToDisplay.className = "p-on-white service-desc"
document.getElementById(target).className = "service-desc";
}
...seems to work. Just an alternative. Hope it helps. In words this is what it is doing: get data-toggle attribute value, use the data-toggle as an id to get the correct div, get the child p (paragraph) within the div, change the class so it is no longer includes p-hide class, move screen to the appropriate div.
If this not good in some way can you please let me know.
The complete solution INCLUDING links that work from the footer even when you AREN'T on the services page go here:
link to heading on different page and make paragraph visible from footer link while not on linked-to page