Pure JS // Hide div when another divs class has been changed - javascript

Note: I can't use jQuery, only vanilla javascript
I'm not really fluent in pure JS. And this time I can't use any external resources (like jquery).
What I need:
If div1 class is active, hide text2
If div2 class is active, hide text1
I made it somehow to work, but my JS doesn't trigger when the class changes dynamic with another javascript code.
Code that triggers the active class
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
}
Code that should trigger hide/show when the class changes
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
What did I do wrong?
Codepen demo

Place your conditions inside click handler.
Add inline visibility style for inactive element
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
}
body {
margin: 3em;
}
.item {
cursor: pointer;
}
a {
padding: 10px;
}
.active {
color: red;
border: 1px solid red;
}
<a class="item text1" onclick="activeClass(this)">show text</a>
<a class="item text2 active" onclick="activeClass(this)">hide text</a>
<br>
<br>
<h1 class="text1s" style='visibility:hidden;'>TEXT 1</h1>
<h1 class="text2s">TEXT 2</h1>
Updated Codepen

Related

Toggling Functions With Event-listeners

I'm currently working on a font size changer for a website and it "works" but is not user-friendly. Right now I have it set up to on click remove the event listeners from the other id's (smBtn On, mdBtn Gone, lgBtn Gone) and return them when none is pressed. Where in actuality, I want it when upon button press it just turns the others off. So I guess my question is how do I toggle my functions
My Idea: One Button is ON forces the other two OFF, when clicked off forces all off Example (Med ON, Sm OFF Lg OFF) (Sm ON, Med OFF, Lg ON) (All OFF)
//Countp and Findp are used in a loop to find all the P tags on a page and then give them the class size
var countP = document.getElementsByTagName('P')
var i;
for (i = 0; i < countP.length; i++) {
var findP = document.getElementsByTagName('P')[i];
findP.setAttribute('class', 'size');
}
//these are all the buttons used to active the functions
document.getElementById("smBtn").addEventListener("click", smallTxt);
document.getElementById("mdBtn").addEventListener("click", mediumTxt);
document.getElementById("lgBtn").addEventListener("click", largeTxt);
//All the functions use the same code just changed Id's and class names that match the small,med,large
function smallTxt() {
// finds all P tags with the Class name Size and then adds the css small
var smButton = document.getElementById("smBtn");
for (i = 0; i < countP.length; i++) {
var smWords = document.getElementsByClassName("size");
[i];
smWords[i].classList.toggle("small");
}
//toggles the css only
smButton.classList.toggle("clicked");
//this is to prevent the other sizes from being clicked by removing the function and when not in use add the functions back
if (smButton.className == "clicked") {
document.getElementById("mdBtn").removeEventListener("click", mediumTxt);
document.getElementById("lgBtn").removeEventListener("click", largeTxt);
} else {
document.getElementById("mdBtn").addEventListener("click", mediumTxt);
document.getElementById("lgBtn").addEventListener("click", largeTxt);
}
}
function mediumTxt() {
var medButton = document.getElementById("mdBtn");
for (i = 0; i < countP.length; i++) {
var medWords = document.getElementsByClassName("size");
[i];
medWords[i].classList.toggle("medium");
}
medButton.classList.toggle("clicked");
if (medButton.className == "clicked") {
document.getElementById("smBtn").removeEventListener("click", smallTxt);
document.getElementById("lgBtn").removeEventListener("click", largeTxt);
} else {
document.getElementById("smBtn").addEventListener("click", smallTxt);
document.getElementById("lgBtn").addEventListener("click", largeTxt);
}
}
function largeTxt() {
var lgButton = document.getElementById("lgBtn");
for (i = 0; i < countP.length; i++) {
var lgWords = document.getElementsByClassName("size");
[i];
lgWords[i].classList.toggle("large");
}
lgButton.classList.toggle("clicked");
if (lgButton.className == "clicked") {
document.getElementById("mdBtn").removeEventListener("click", mediumTxt);
document.getElementById("smBtn").removeEventListener("click", smallTxt);
} else {
document.getElementById("mdBtn").addEventListener("click", mediumTxt);
document.getElementById("smBtn").addEventListener("click", smallTxt);
}
}
.small {
font-size: 10px;
}
.medium {
font-size: 20px;
}
.large {
font-size: 30px;
}
.clicked {
color: #012169;
text-shadow: 2px 2px 4px #000000;
}
ul li {
display: inline-block;
}
<h2>Font Text Changer V2</h2>
<p>Click on one of the a's next to font size to change the size of the text, only one A can be active at a time their for must turn it off to use other sizes</p>
<p>Developer Idea:One Button is ON forces the other two OFF, when clicked off forces all off Example (Med ON, Sm OFF Lg OFF) (Sm ON, Med OFF, Lg ON) (All OFF) </p>
<p> Beneath is how you test the the function</p>
<ul>
<li style="font-size:14px">Font size:</li>
<li id="smBtn" style="font-size:13px">A</li>
<li id="mdBtn" style="font-size:17px">A</li>
<li id="lgBtn" style="font-size:20px">A</li>
</ul>
An easier way would be to change the font-size of the html tag by adding classes with javascript. Then all child elements will follow. I.E.:
html {
font-size: 100%; //16px
}
html.small {
font-size: 75% //12px
}
html.big {
font-size: 125% //20px
}
I would delegate
document.querySelectorAll('P').forEach(p => p.setAttribute('class', 'size'));
document.getElementById("fontList").addEventListener("click", function(e) {
const tgt = e.target.closest(".btn");
if (tgt) {
let clicked = this.querySelector(".clicked")
if (clicked && clicked != tgt) return; // you need to click again
tgt.classList.toggle("clicked"); // toggle on and off
clicked = this.querySelector(".clicked"); // find the one clicked
document.querySelectorAll(".size").forEach(p => {
if (clicked) p.classList.toggle(clicked.dataset.size); // add or remove
else p.className = "size"; // remove all
})
}
})
.small {
font-size: 10px;
}
.medium {
font-size: 20px;
}
.large {
font-size: 30px;
}
.clicked {
color: #012169;
text-shadow: 2px 2px 4px #000000;
}
ul li {
display: inline-block;
}
<h2>Font Text Changer V2</h2>
<p>Click on one of the a's next to font size to change the size of the text, only one A can be active at a time their for must turn it off to use other sizes</p>
<p>Developer Idea:One Button is ON forces the other two OFF, when clicked off forces all off Example (Med ON, Sm OFF Lg OFF) (Sm ON, Med OFF, Lg ON) (All OFF) </p>
<p> Beneath is how you test the the function</p>
<ul id="fontList">
<li style="font-size:14px">Font size:</li>
<li class="btn" data-size="small" style="font-size:13px">A</li>
<li class="btn" data-size="medium" style="font-size:17px">A</li>
<li class="btn" data-size="large" style="font-size:20px">A</li>
</ul>
Selecting fonts from li elements is not ideal but in this particular setup one way of doing the job could be;
var choices = document.querySelectorAll("li:nth-child(n+2)"),
context = document.querySelectorAll("p");
choices.forEach(choice => choice.addEventListener("click", e => context.forEach(p => p.style.fontSize = e.target.style.fontSize)));
<h2>Font Text Changer V2</h2>
<p>Click on one of the a's next to font size to change the size of the text, only one A can be active at a time their for must turn it off to use other sizes</p>
<p>Developer Idea:One Button is ON forces the other two OFF, when clicked off forces all off Example (Med ON, Sm OFF Lg OFF) (Sm ON, Med OFF, Lg ON) (All OFF) </p>
<p> Beneath is how you test the the function</p>
<ul>
<li style="font-size:14px">Font size:</li>
<li id="smBtn" style="font-size:13px">A</li>
<li id="mdBtn" style="font-size:17px">A</li>
<li id="lgBtn" style="font-size:20px">A</li>
</ul>

How to get JS tab selector to not scroll

I'm using this JS for tabs. However, it continually makes the selected tab box scroll to the top of the page when clicked.
I can't figure out what part of it is doing that and am trying to get rid of it. Essentially I just want it to function as a normal tab clicker without causing the entire page to scroll.
Any help?
I added a snippet with a large top margin so you can see what happens when you click the tab. I just want those boxes to change without the page physically scrolling to them on its own.
'use strict';
function Tabs() {
var bindAll = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].addEventListener('click', change, false);
}
}
var clear = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].classList.remove('active');
var id = menuElements[i].getAttribute('data-tab');
document.getElementById(id).classList.remove('active');
}
}
var change = function(e) {
clear();
e.target.classList.add('active');
var id = e.currentTarget.getAttribute('data-tab');
document.getElementById(id).classList.add('active');
}
bindAll();
}
var connectTabs = new Tabs();
.b-box {margin-top: 1500px;}
.b-tab {
padding: 20px;
border: 1px solid #000;
display: none
}
.b-tab.active {
display: block;
}
.b-nav-tab {
display: inline-block;
padding: 20px;
}
.b-nav-tab.active {
color: #ff4200;
}
<a href="#orange" data-tab="orange" class="b-nav-tab active">
Orange
</a>
<a href="#green" data-tab="green" class="b-nav-tab">
Green
</a>
<a href="#blue" data-tab="blue" class="b-nav-tab">
Blue
</a>
<div class="b-box">
<div id="orange" class="b-tab active">
Orange tab content
</div>
<div id="green" class="b-tab">
Green tab content
</div>
<div id="blue" class="b-tab">
Blue tab content
</div></div>
I updated your code.
Actually you was showing # sign in href so it redirect the position to that box. I removed it.
Good Luck.
'use strict';
function Tabs() {
var bindAll = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].addEventListener('click', change, false);
}
}
var clear = function() {
var menuElements = document.querySelectorAll('[data-tab]');
for (var i = 0; i < menuElements.length; i++) {
menuElements[i].classList.remove('active');
var id = menuElements[i].getAttribute('data-tab');
document.getElementById(id).classList.remove('active');
}
}
var change = function(e) {
clear();
e.target.classList.add('active');
var id = e.currentTarget.getAttribute('data-tab');
document.getElementById(id).classList.add('active');
}
bindAll();
}
var connectTabs = new Tabs();
.b-tab {
padding: 20px;
border: 1px solid #000;
display: none;
}
.b-tab.active {
display: block;
}
.b-nav-tab {
display: inline-block;
padding: 20px;
}
.b-nav-tab.active {
color: #ff4200;
}
<a href="javascript:void(0)" data-tab="orange" class="b-nav-tab active">
Orange
</a>
<a href="javascript:void(0)" data-tab="green" class="b-nav-tab">
Green
</a>
<a href="javascript:void(0)" data-tab="blue" class="b-nav-tab">
Blue
</a>
<div id="orange" class="b-tab active">
Orange tab content
</div>
<div id="green" class="b-tab">
Green tab content
</div>
<div id="blue" class="b-tab">
Blue tab content
</div>
One way would be to add this e.preventDefault(); to your change function and the other way would be to replace href="#orange" with href="javascript:void(0)". All the same with other hrefs.

access to shadow dom properties

so here is my script code
class Pop extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
let currDoc = document.currentScript.ownerDocument;
let template = currDoc.querySelector('#pop-up');
let tmplNode = document.importNode(template.content, true);
let shadowRoot = this.createShadowRoot();
shadowRoot.appendChild(tmplNode);
shadowRoot.querySelector("#content").innerHTML = this.innerHTML;
}
}
window.customElements.define("pop-up", Pop);
and here is my template
<template id="pop-up">
<style>
* {
padding: 0;
margin: 0;
}
.btn {
//styling
}
.btn:hover {
//styling
}
#box{
//styling
display: none;
}
#box h1{
//styling
}
</style>
<div id="box">
<h1> Your Shopping Cart</h1>
<text id="content"> </text>
<button class="btn" onclick="close()"> Close </button>
</div>
</template>
and in my index file i have this
<button class="btn" onclick="pop()">Show Pop</button>
<pop-up id="pop"> pop-up box</pop-up>
<script>
function pop(){
document.getElementById("pop").style.display = "block";
}
</script>
I am trying to do a pop-up box. And when i click on the "Show Pop" button i want to change the display property from style to "block" from "none". But for some reason it doesn't work. Im new to this shadow dom elemets and i can't really figure it out.
It is hard to explain everything in this answer, but the following code will give you an overview of how the solution might look like.
MDN, as usual, has the perfect intro for web components and shadow doms here
class Pop extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
let template = document.getElementById('pop-up');
let templateContent = template.content;
// Create a shadow root
const shadowRoot = this.attachShadow({ mode: 'open' })
.appendChild(templateContent.cloneNode(true));
// attach close listener
this.shadowRoot.querySelector('.btn').addEventListener('click', this.close.bind(this));
}
// close pop-up
close() {
this.style.display = 'none';
}
// open pop-up
open() {
this.style.display = 'block';
}
}
window.customElements.define("pop-up", Pop);
function pop() {
// notice we are using the open method here
document.getElementById("pop").open();
}
<template id="pop-up">
<style>
:host {
display: none;
}
* {
padding: 0;
margin: 0;
}
.btn {
//styling
}
.btn:hover {
//styling
}
#box {
//styling
display: none;
}
#box h1 {
//styling
}
</style>
<div id="box">
<h1> Your Shopping Cart</h1>
<!-- Notice we are using slots -->
<slot> </slot>
<button class="btn"> Close </button>
</div>
</template>
<button class="btn" onclick="pop()">Show Pop</button>
<pop-up id="pop"> pop-up box </pop-up>

How to change style of elements that aren't "(obj)"

I have multiple items in a row that I want to easily change the style of the border based on my selection.
Here is the HTML of just the row and some of the items in it:
<div class="items">
<ul>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3001.png" alt="Abyssal Scepter" id="as">
</span>
</li>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3020.png" alt="Sorcerer's Shoes" id="ss">
</span>
</li>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3025.png" alt="Iceborn Gauntlet" id="ig">
</span>
</li>
</ul>
</div>
I have tried to do if !(obj).style..... However that won't work and I cannot find any solutions anywhere.
I Know how to do this with states and cases. However, I didn't want my JS to be a few 100 lines long.
So here is my js
var as = document.getElementById('as');
var ss = document.getElementById('ss');
var ig = document.getElementById('ig');
as.addEventListener('click', function() {
ItemDisc('as');
});
ss.addEventListener('click', function() {
ItemDisc('ss');
});
ig.addEventListener('click', function() {
ItemDisc('ig');
});
function ItemDisc(obj) {
var change = document.getElementById(obj);
var changeback = document.getElementById(!obj);
change.style.border = "5px solid blue";
for(!obj) {
changeback.style.border = "5px solid blue";
}
}
You can also use this as your JS:
var imgs = document.getElementsByClassName('item-img');
for(i=0; i<imgs.length; i++) {
imgs[i].addEventListener('click', function(){
for (i=0; i<imgs.length; i++)
imgs[i].style.border='1px solid blue';
this.style.border = '1px solid red';
});
}
This is a basic demo that could be improved upon.
The main idea is to loop through all the items and "reset" them to their default state. Then apply the selection style to the selected element.
<div class="items">
<ul>
<li>
<img src="https://placehold.it/50x50&text=01">
</li>
<li>
<img src="https://placehold.it/50x50&text=02">
</li>
<li>
<img src="https://placehold.it/50x50&text=03">
</li>
</ul>
</div>
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
margin: 0 1rem;
}
.highlight {
border: 2px solid red;
}
// Get all items.
var items = document.querySelectorAll( '.items li' );
// Adding/removing selection style via a CSS class.
function addHighlight() {
// Loop through all items and remove the selection class.
for ( var i = 0, len = items.length; i < len; i++ ) {
items[i].className = items[i].className.replace( 'highlight', '' );
}
// Add selection class to selected item.
this.className += ' highlight';
}
// Add click event handler to items.
function addEventListener( items, event, listener ) {
for ( var i = 0, len = items.length; i < len; i++ ) {
items[ i ].addEventListener( event, listener );
}
}
addEventListener( items, 'click', addHighlight );
Demo JSFiddle.
I dont understand what you are trying to do, so I can't recreate something in its entirety.
I can point you in the right direction though.
Your problem is on line
var changeback = document.getElementById(!obj)
!obj is being resolved to the Boolean 'false', and not the element you are selecting.
Furthermore, you are using 'for', when you should be using 'if'
For is creating loops, and 'if' is for conditions
if(!obj) {
changeback.style.border = "5px solid blue";
}
Also, the border color is exactly the same.
I think it is possible to achieve what you want by changing your ItemDisc(obj) function to this.
function ItemDisc(obj){
element = document.getElementById(obj);
if(element.classList.contains('active')){
element.className += " active";
element.style.border = "5px solid blue";
} else {
element.className = "";
// Careful, because this will remove all classes from your element.
}
}
Just wanted to say... This is without jQuery, also, you can make it easier by adding styles to your css class 'active' which included borders.
}
This is very simple to do with jQuery. I'd recommend learning jQuery because it will familiarize you with both css-selectors and JavaScript. Here's a boilerplate to get you started, please forgive any typos:
<style>
.active{border:5px solid #0000FF;}
</style>
$(".item-img").click(function(){
.each(".item-img"){
myFunction( $(this).attr("id") );
}
});
function myFunction(theID){
if( $(this).attr("id") == theID ){
$(this).addClass("active");
}else{
$(this).removeClass("active");
}
}
You will want to load jQuery in your html. Also, you'll need to wrap the js above in:
$(document).ready(function(){/*above code goes here*/});

Make div in div clickable with Javascript

Have a problem and can't get to solve it. Tried to use QuerySelectorAll and comma separating with GetElementsByClassName, but that didn't work, so I am wondering how to solve this problem.
I have this HTML:
<div class="area">Test title
<div class="some content" style="display: none">blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
<div class="area">
Test title
<div class="some content">
blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
JS:
function areaCollapse() {
var next = this.querySelector(".content");
if (this.classList.contains("open")) {
next.style.display = "none";
this.classList.remove("open");
} else {
next.style.display = "block";
this.classList.add("open");
}
}
var classname = document.getElementsByClassName("area");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', areaCollapse, true);
}
http://jsfiddle.net/1BJK903/nb1ao39k/6/
CSS:
.two {
position: absolute;
top: 0;
}
So now, the div with classname "area" is clickable. I positioned the div with class "two" absolute and now the whole div is clickable, except where this other div is. If you click on the div with classname "two", it doesn't work (it does not collapse or open the contents). How can I make this work, without changing the structure?
One way is using a global handler, where you can handle more than one item by checking its id or class or some other property or attribute.
Below snippet finds the "area" div and pass it as a param to the areaCollapse function. It also check so it is only the two or the area div (colored lime/yellow) that was clicked before calling the areaCollapse.
Also the original code didn't have the "open" class already added to it (the second div group), which mean one need to click twice, so I change the areaCollapse function to check for the display property instead.
function areaCollapse(elem) {
var next = elem.querySelector(".content");
if (next.style.display != "none") {
next.style.display = "none";
} else {
next.style.display = "block";
}
}
window.addEventListener('click', function(e) {
//temp alert to check which element were clicked
//alert(e.target.className);
if (hasClass(e.target,"area")) {
areaCollapse(e.target);
} else {
//delete next line if all children are clickable
if (hasClass(e.target,"two")) {
var el = e.target;
while ((el = el.parentElement) && !hasClass(el,"area"));
if (targetInParent(e.target,el)) {
areaCollapse(el);
}
//delete next line if all children are clickable
}
}
});
function hasClass(elm,cln) {
return (" " + elm.className + " " ).indexOf( " "+cln+" " ) > -1;
}
function targetInParent(trg,pnt) {
return (trg === pnt) ? false : pnt.contains(trg);
}
.area {
background-color: lime;
}
.two {
background-color: yellow;
}
.area:hover, .two:hover {
background-color: green;
}
.some {
background-color: white;
}
.some:hover {
background-color: white;
}
<div class="area">Test title clickable 1
<div class="some content" style="display: none">blablbala NOT clickable 1
</div>
<div class="two">This should be clickable too 1</div>
</div>
<div class="area">Test title clickable 2
<div class="some content">blablbala NOT clickable 2
</div>
<div class="two">This should be clickable too 2</div>
</div>
<div class="other">This should NOT be clickable</div>
You need to find your two elements while you're binding classname, and bind that as well.
var classname = document.getElementsByClassName("area");
for(var i=0; i < classname.length; i++){
classname[i].addEventListener('click', areaCollapse, true);
var twoEl = classname[i].getElementsByClassName("two")[0];
twoEl.addEventListener('click', function(e) { console.log('two clicked'); });
}
If you want to use jQuery:
$('.two').click(function(){
//action here
});

Categories

Resources