I want to add active class to the one element and remove that class from all other 'article' elements, hide them. Just normal javascript tabs.
I'm new in JS and can't resolve this problem.
Here is my Fiddle: https://jsfiddle.net/a8bvp0fn/
SOLVED: https://jsfiddle.net/y8sa3e0c/
thx
<style>
.article-1, .article-2, .article-3 {
width: 100px;
height: 200px;
display: none;
}
.article-1 {
background: red;
}
.article-2 {
background: green;
}
.article-3 {
background: blue;
}
.active {
display: inline-block;
}
</style>
<h2 class="output" data-tab="1">BUTTON 1</h2>
<h2 class="output" data-tab="2">BUTTON 2</h2>
<h2 class="output" data-tab="3">BUTTON 3</h2>
<div class="article-1"></div>
<div class="article-2"></div>
<div class="article-3"></div>
<script>
var output = document.querySelectorAll('.output');
output.forEach(function(item) {
item.onclick = function(){
var datas = this.dataset.tab;
var elem = document.querySelector('.article-' + datas);
elem.classList.toggle('active');
}
});
</script>
var output = document.querySelectorAll('.output');
output.forEach(function(item) {
item.onclick = function() {
var datas = this.dataset.tab;
var elem = document.querySelector('.article-' + datas);
let AllElems = document.querySelector('.active');
if (AllElems) {
AllElems.classList.remove('active');
}
elem.classList.add("active");
}
});
.article-1,
.article-2,
.article-3 {
width: 100px;
height: 200px;
display: none;
}
.article-1 {
background: red;
}
.article-2 {
background: green;
}
.article-3 {
background: blue;
}
.active {
display: inline-block;
}
<h2 class="output" data-tab="1">BUTTON 1</h2>
<h2 class="output" data-tab="2">BUTTON 2</h2>
<h2 class="output" data-tab="3">BUTTON 3</h2>
<div class="article-1"></div>
<div class="article-2"></div>
<div class="article-3"></div>
One solution would be to get all the article elements with:
var articles = document.getElementsByClassName('article');
And then in the onclick method, remove the active class from all articles other than the one you clicked:
for (let i = 0; i< articles.length; i++) {
if (articles[i] !== elem) {
articles[i].classList.remove('active');
} else {
articles[i].classList.toggle('active');
}
}
var output = document.querySelectorAll('.output');
function hideAll(){
//Function to hide all active divs
var allActive = document.querySelectorAll('.active');
allActive.forEach(function(item) {
item.classList.remove('active')
})
}
output.forEach(function(item) {
//Adding click listener on articles
item.onclick = function(){
var datas = this.dataset.tab;
var elem = document.querySelector('.article-' + datas);
if(elem.classList.contains('active')){
//If already active remove
elem.classList.remove('active')
}
else{
//If not already active, before add active remove all
hideAll()
elem.classList.add('active')
}
}
});
.article-1, .article-2, .article-3 {
width: 100px;
height: 200px;
display: none;
}
.article-1 {
background: red;
}
.article-2 {
background: green;
}
.article-3 {
background: blue;
}
.active {
display: inline-block;
}
<h2 class="output" data-tab="1">BUTTON 1</h2>
<h2 class="output" data-tab="2">BUTTON 2</h2>
<h2 class="output" data-tab="3">BUTTON 3</h2>
<div class=" article-1"></div>
<div class=" article-2"></div>
<div class=" article-3"></div>
Easiest solution: Just remove the class for all elements, then add like you did.
var output = document.querySelectorAll('.output');
output.forEach(function(item)
{
item.onclick = function()
{
var datas = this.dataset.tab;
// ---------------- so just add this bit..
var alltabs=document.getElementsByTagName("div");
for(var i=0;i<alltabs.length;i++)
{
alltabs[i].classList.remove('active');
}
// ---------------- and then go on like you did.. (only don't toggle, just add)
var elem = document.querySelector('.article-' + datas);
elem.classList.add('active');
}
});
Related
I am trying to create a custom HTML component which creates tabs for every child element that it has. Here is the code for that custom component:
const code_window = document.getElementById("window");
class CodeWindow extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'
});
this.shadowRoot.appendChild(code_window.content.cloneNode(true));
this.code = this.shadowRoot.getElementById("code");
this.tabbar = this.shadowRoot.getElementById("tabbar");
this.code.addEventListener("slotchange", e => {
var elems = e.target.assignedNodes();
for (let i = 0; i < elems.length; i++) {
var tab = document.createElement("div");
tab.classList.add("tab");
var name = elems[i].getAttribute("name");
tab.innerHTML = name;
tab.setAttribute("name", name);
this.tabbar.appendChild(tab);
if (elems[i].hasAttribute("active")) this.activateTab(name);
tab.addEventListener("click", e => this.activateTab(e.target.getAttribute("name")));
}
if (!this.previous_tab && this.tabbar.children.length > 0) this.activateTab(this.tabbar.children[0].getAttribute("name"));
});
}
activateTab(name) {
if (this.previous_tab) {
this.previous_frame.removeAttribute("active");
this.previous_tab.removeAttribute("active");
}
var tabs = this.tabbar.children,
frames = this.code.assignedElements();
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].getAttribute("name") == name) {
tabs[i].setAttribute("active", "");
frames[i].setAttribute("active", "");
this.previous_frame = frames[i];
this.previous_tab = tabs[i];
break;
}
}
}
}
customElements.define("c-window", CodeWindow);
<template id="window">
<style>
:host {
display: flex;
flex-direction: column;
}
#titlebar {
display: flex;
background-color: green;
}
#tabbar {
flex-grow: 1;
display: flex;
}
#tabbar .tab {
display: flex;
align-items: center;
padding: 5px 10px;
background-color: #bbb;
}
#tabbar .tab[active] {
background-color: #fff;
}
#code {
flex-grow: 1;
display: block;
position: relative;
}
#code::slotted(*) {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 5px;
display: none;
}
#code::slotted(*[active]) {
display: block;
}
</style>
<div id="titlebar">
<div id="tabbar"></div>
</div>
<slot id="code" name="frames"></slot>
</template>
<c-window style="border: 2px solid green; height: 300px;">
<div slot="frames" name="Content 1">Contents of tab 1</div>
<div slot="frames" name="Content 2">Contents of tab 2</div>
</c-window>
There is a slot inside the custom component and I want that every time a child element is added, a tab should be added, if a child element is removed, the tab associated with that child should be removed.
But the slotchange event carries no information about which element has been added/removed, so currently, I have to loop through the slot.assignedElements() every time slotchange event is called and create tabs for each and every element. It means that for a particular child, duplicate tabs will be created, which can also be quite CPU intensive.
So, I was thinking if there is some way to get the information about the modified element so that the action can be performed on only the modified element. Is there any way of getting only the modified element? If not, what method can I apply for achieving this?
You are doing the oldskool Switch-DIVs approach for Tabs
You can do it all with one shadowDOM <slot ="active">
and one click handler
Needs some more work; but you get the slot="active" concept
<template id="TABS-MEISTER">
<style>
#bar { display:flex }
#bar div { width: 100px; background: lightgreen ; margin-right:1em ; cursor:pointer}
</style>
<div id="bar"></div>
<div style="clear:both"><slot name="active"></slot></div>
</template>
<tabs-meister>
<div title="Tab1">Tab #1</div>
<div slot="active" title="Tab2">Tab #2</div>
<div title="Tab3">Tab #3</div>
</tabs-meister>
<script>
customElements.define('tabs-meister', class extends HTMLElement {
constructor() {
let template = (id) => document.getElementById(id).content.cloneNode(true);
super()
.attachShadow({mode: 'open'})
.append(template(this.nodeName));
this.onclick = (evt) => {
if (this.activetab) this.activetab.removeAttribute("slot");
let tab = evt.composedPath()[0];
this.activetab = this.querySelector(`[title="${tab.title}"]`);
this.activetab.slot = 'active';
}
}
connectedCallback() {
let tabs = [...this.children].map(node => {
return `<div title=${node.title}>${node.title}</div>`;
}).join ``;
this.shadowRoot.querySelector("#bar").innerHTML = tabs;
}
});
</script>
$(document).ready(function() {
$(".show_on_hover").click(function() {
$(".show_on_hover.hover").not(this).removeClass("hover");
$(this).toggleClass("hover");
});
});
Any clever JavaScript person know how to write the above as plain JavaScript? Thanks in advance :)
Here's the intended behavior: https://jsfiddle.net/kevadamson/fr8usm19/
Here is your original (using jQuery):
$(document).ready(function() {
$(".show_on_hover").click(function() {
$(".show_on_hover.hover").not(this).removeClass("hover");
$(this).toggleClass("hover");
});
});
div {
display: inline-block;
width: 100px;
height: 100px;
margin: 3px;
background-color: rgb(255, 0, 0);
cursor: pointer;
}
.show_on_hover {
opacity: 0.3;
}
.show_on_hover:hover,
.show_on_hover.hover {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
Here is the same setup, with jQuery translated into javascript:
// Equivalent to $(".show_on_hover")
let showOnHoverDivs = [...document.getElementsByClassName('show_on_hover')];
const showHideDivs = (event) => {
for (let showOnHoverDiv of showOnHoverDivs) {
// Equivalent to .not(this)
if (showOnHoverDiv === event.target) continue;
// Equivalent to .removeClass("hover")
showOnHoverDiv.classList.remove('hover');
}
// Equivalent to $(this).toggleClass("hover")
event.target.classList.toggle('hover');
}
// Equivalent to $(".show_on_hover").click(function() { [...] }
for (let showOnHoverDiv of showOnHoverDivs) {
showOnHoverDiv.addEventListener('click', showHideDivs, false);
}
div {
display: inline-block;
width: 100px;
height: 100px;
margin: 3px;
background-color: rgb(255, 0, 0);
cursor: pointer;
}
.show_on_hover {
opacity: 0.3;
}
.show_on_hover:hover,
.show_on_hover.hover {
opacity: 1;
}
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
<div class="show_on_hover"></div>
Add click listener only for the first element with class .show_on_hover:
const btn = document.querySelector('.show_on_hover');
btn.addEventListener('click', () => {
if (btn.classList.contains('hover')) {
btn.classList.remove('hover');
} else {
btn.classList.add('hover');
}
})
Add click listener for each element with class .show_on_hover:
const btns = document.querySelectorAll('.show_on_hover');
btns.forEach(el => el.addEventListener('click', () => {
if (btn.classList.contains('hover')) {
el.classList.remove('hover');
} else {
el.classList.add('hover');
}
}));
you can use classList
you can do toggle, remove, add, and also with condition
var btn = document.querySelector('.show_on_hover')
btn.classList.toggle('hover);
i'm trying to develop a game using html, css and js. At the moment I'm focusing on manipulating DOM elements without using the canvas tag. My idea is to create a pseudo graphical programming language, similar to the Blockly environment. So far I have inserted 3 clickable elements inside #toolbox that create their copies in #workspace.
Now, I am trying to assign functions to the elements present in #workspace, which once pressed the Run button are executed in order of appearance, so as to create a queue of commands that is able to move the pink square inside #output_section.
Therefore I cannot understand how to write the function that is able to verify the presence of the elements and then be able to perform the different functions assigned to these elements.
Any ideas? :D
I'm using Jquery 3.3.1
function addRed() {
var redWorkspace = document.createElement("DIV");
redWorkspace.className = "remove-block block red";
document.getElementById("workspace").appendChild(redWorkspace);
};
function addBlue() {
var blueWorkspace = document.createElement("DIV");
blueWorkspace.className = "remove-block block blue";
document.getElementById("workspace").appendChild(blueWorkspace);
};
function addGreen() {
var greenWorkspace = document.createElement("DIV");
greenWorkspace.className = "remove-block block green";
document.getElementById("workspace").appendChild(greenWorkspace);
};
$("#clear_workspace").click(function () {
$("#workspace").empty();
});
$(document).on("click", ".remove-block", function () {
$(this).closest("div").remove();
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
bottom: 0;
right: 0;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<body>
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div onclick="addRed()" class="block red">Left</div>
<div onclick="addBlue()" class="block blue">Up</div>
<div onclick="addGreen()" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>
</body>
</html>
Completely untested but run button does something along the lines of:
$("#run_workspace").click(function() {
$("#workspace .block").each(function(elem) {
if (elem.hasClass("red")) {
moveObjectLeft();
} else if (elem.hasClass("green")) {
moveObjectRight();
} else if (elem.hasClass("blue")) {
moveObjectUp();
}
});
});
Commonly, it's a good idea to store all required information in arrays and objects, and use HTML only to display your data.
Also, if you are already using jQuery - use it for all 100%)
Made some improvements:
let mobs = {
pinky: {
node: $('#moving_square'),
coors: { top: 400, left: 400 },
step: 30,
moveQueue: [],
// moveTimeout ???
},
}; // storing here all created objects, that must move.
/* Each [moveQueue] array will store the chain of moves, like ["up", "up", "left"]
You can take each "key-word" of move, and get required function buy that key,
from the 'move' object */
let move = { // Think about how to simlify this object and functions. It's possible!)
left: function (obj) {
let left = obj.coors.left = (obj.coors.left - obj.step);
obj.node.css('left', left + 'px');
},
up: function (obj) {
let top = obj.coors.top = (obj.coors.top - obj.step);
obj.node.css('top', top + 'px');
},
right: function (obj) {
let left = obj.coors.left = (obj.coors.left + obj.step);
obj.node.css('left', left + 'px');
}
};
let stepTimeout = 1000;
let running = false;
let timeouts = {}; // store all running timeouts here,
// and clear everything with for( key in obj ) loop, if required
$('#toolbox .block').on('click', function () {
let color = $(this).attr('data-color');
let workBlock = '<div class="remove-block block ' + color + '"></div>';
$('#workspace').append(workBlock);
mobs.pinky.moveQueue.push( $(this).text().toLowerCase() ); // .attr('data-direction');
// instead of pinky - any other currently selected object
// $(this).text().toLowerCase() — must be "left", "up", "right"
});
$('#run_workspace').on('click', function () {
running = true;
runCode();
function runCode() {
for (let obj in mobs) { // mobile objects may be multiple
// Inside the loop, obj == mobs each key name. Here it's == "pinky"
let i = 0;
let pinky = mobs[obj];
localRun();
function localRun() {
let direction = pinky.moveQueue[i]; // getting direction key by array index.
move[direction](pinky); // calling the required function from storage.
if (pinky.moveQueue[++i] && running ) {
// self-calling again, if moveQueue has next element.
// At the same time increasing i by +1 ( ++i )
timeouts[obj] = setTimeout(localRun, stepTimeout);
}
}
}
}
});
$("#clear_workspace").click(function () {
$("#workspace").empty();
});
$('#workspace').on("click", ".remove-block", function () {
$(this).closest("div").remove();
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
top: 400px;
left: 400px;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div data-color="red" class="block red">Left</div>
<div data-color="blue" class="block blue">Up</div>
<div data-color="green" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>
But... jQuery was used only for clicks... Translation to JS:
let mobs = {
pinky: {
node: document.getElementById('moving_square'),
coors: { top: 400, left: 400 },
step: 30,
moveQueue: [],
},
};
let move = {
left: function (obj) {
let left = obj.coors.left = (obj.coors.left - obj.step);
obj.node.style.left = left + 'px';
},
up: function (obj) {
let top = obj.coors.top = (obj.coors.top - obj.step);
obj.node.style.top = top + 'px';
},
right: function (obj) {
let left = obj.coors.left = (obj.coors.left + obj.step);
obj.node.style.left = left + 'px';
}
};
let stepTimeout = 1000;
let running = false;
let timeouts = {};
let blocks = document.querySelectorAll('#toolbox .block');
let workSpace = document.getElementById('workspace');
blocks.forEach(function(block){
block.addEventListener('click', function(){
let color = this.dataset.color;
let workBlock = '<div class="remove-block block ' + color + '"></div>';
workSpace.insertAdjacentHTML('beforeend', workBlock);
mobs.pinky.moveQueue.push( this.textContent.toLowerCase() );
});
});
document.getElementById('run_workspace').addEventListener('click', function () {
running = true;
runCode();
function runCode() {
for (let obj in mobs) { // mobile objects may be multiple
// Inside the loop, obj == mobs each key name. Here it's == "pinky"
let i = 0;
let pinky = mobs[obj];
localRun();
function localRun() {
let direction = pinky.moveQueue[i]; // getting direction key by array index.
move[direction](pinky); // calling the required function from storage.
if (pinky.moveQueue[++i] && running ) {
// self-calling again, if moveQueue has next element.
// At the same time increasing i by +1 ( ++i )
timeouts[obj] = setTimeout(localRun, stepTimeout);
}
}
}
}
});
document.getElementById("clear_workspace").addEventListener('click', function () {
workSpace.textContent = "";
});
workSpace.addEventListener('click', function (e) {
if( e.target.classList.contains('remove-block') ){
e.target.remove();
}
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
top: 400px;
left: 400px;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div data-color="red" class="block red">Left</div>
<div data-color="blue" class="block blue">Up</div>
<div data-color="green" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>
strong text
I have a box in a few boxes and placed inside each box for an hour.
I want to sort by using the box clock named item.
This sorting has three modes, the first ascending, the second descending, the third without sorting.
strong text
<body>
<style>
body{margin: 0 auto;padding: 0 auto;background: skyblue;}
.full-item{width: 800px;height: 600px;margin: 50px auto;background: grey;}
.full-item .button-item{width: 100%;height: 80px;background: #B33771;}
.full-item .button-item button{margin: 30px 45%;}
.full-item .item-sort{width: 100%;height: 500px;background: white;margin-top: 10px;}
.full-item .item-sort:first-child{margin-top: 10px;}
.full-item .item-sort .item{width: 90%;height: 140px;background: red;margin: 10px auto;}
.item-sort .item .pic{width: 30%;height: 100%;background: #3B3B98;float: left;}
.item-sort .item .time{width: 70%;height: 100%;background: #1B9CFC;float: right;}
.item-sort .item .time span{color: white;text-align: center;display: block;line-height: 100px;}
</style>
<div class="full-item">
<div class="button-item">
<button id="Sort-item">Sort by</button>
</div>
<div class="item-sort">
<div class="item">
<div class="pic"></div>
<div class="time"><span>15:20</span></div>
</div>
<div class="item">
<div class="pic"></div>
<div class="time"><span>13:10</span></div>
</div>
<div class="item">
<div class="pic"></div>
<div class="time"><span>18:40</span></div>
</div>
</div>
</div>
</body>
If the data is coming from JSON or other source, as with akbansa's recommendation, you should perform the sorting on the data first; otherwise, see below for an example of how you could reorder your elements:
const button = document.querySelector('#Sort-item')
// add handler
button.addEventListener('click', clickHandler)
// handler definition
function clickHandler(){
let container = document.querySelector('.item-sort')
let items = Array.from(container.querySelectorAll('.item-sort .item'))
// sort based on time
items = items.sort((a,b)=>{
let a_time = a.querySelector('.time span').textContent
let b_time = b.querySelector('.time span').textContent
return a_time > b_time ? 1 : -1
})
// apply the order
for(let item of items)
container.appendChild(item)
}
body {
margin: 0 auto;
padding: 0 auto;
background: skyblue;
}
.full-item {
width: 800px;
height: 600px;
margin: 50px auto;
background: grey;
}
.full-item .button-item {
width: 100%;
height: 80px;
background: #B33771;
}
.full-item .button-item button {
margin: 30px 45%;
}
.full-item .item-sort {
width: 100%;
height: 500px;
background: white;
margin-top: 10px;
}
.full-item .item-sort:first-child {
margin-top: 10px;
}
.full-item .item-sort .item {
width: 90%;
height: 140px;
background: red;
margin: 10px auto;
}
.item-sort .item .pic {
width: 30%;
height: 100%;
background: #3B3B98;
float: left;
}
.item-sort .item .time {
width: 70%;
height: 100%;
background: #1B9CFC;
float: right;
}
.item-sort .item .time span {
color: white;
text-align: center;
display: block;
line-height: 100px;
}
<div class="full-item">
<div class="button-item">
<button id="Sort-item">Sort by</button>
</div>
<div class="item-sort">
<div class="item">
<div class="pic"></div>
<div class="time"><span>15:20</span></div>
</div>
<div class="item">
<div class="pic"></div>
<div class="time"><span>13:10</span></div>
</div>
<div class="item">
<div class="pic"></div>
<div class="time"><span>18:40</span></div>
</div>
</div>
</div>
Update your html inside "button-item" class
<div class="button-item">
<p>Sort By </p>
<button id="sort-asc" onclick="app.sortAsc()">Asc</button>
<button id="sort-desc" onclick="app.sortDesc()">Desc</button>
<button id="reset" onclick="app.reset()">Reset</button>
</div>
Add to your scripts
var app = (function (){
var originalArr = []
var timeArr = []
var sortedArr = []
var objArr = []
var timeElements = document.querySelectorAll('.time')
var itemSortElement = document.querySelector('.item-sort')
for ( let timeEl of timeElements) {
// retrieving text from individual span element
let timeText = timeEl.children[0].innerText;
// retrieving parent node of div with class "time"
let timeParent = timeEl.parentNode
let obj = { text: timeText, parent: timeParent }
objArr.push(obj)
timeArr.push(timeText)
}
// copying all elements/ texts from "timeArr" array to "originalArr" array
// to keep track of original order of texts
originalArr = timeArr.slice()
function sortAsc () {
// sorting the retrieved texts in ascending order
sortedArr = timeArr.sort();
while (itemSortElement.hasChildNodes()) {
// removing all child elements of class "item-sort"
itemSortElement.removeChild(itemSortElement.firstChild);
}
for ( let i = 0; i < sortedArr.length; i++) {
let filteredObj = objArr.filter((obj) => sortedArr[i] == obj.text)[0]
let node = filteredObj.parent
itemSortElement.appendChild(node)
}
}
function sortDesc () {
sortedArr = timeArr.sort().reverse();
while (itemSortElement.hasChildNodes()) {
itemSortElement.removeChild(itemSortElement.firstChild);
}
for ( let i = 0; i < sortedArr.length; i++) {
var filteredObj = objArr.filter((obj) => sortedArr[i] == obj.text)[0]
let node = filteredObj.parent
itemSortElement.appendChild(node)
}
}
function reset () {
while (itemSortElement.hasChildNodes()) {
itemSortElement.removeChild(itemSortElement.firstChild);
}
for ( let i = 0; i < originalArr.length; i++) {
var filteredObj = objArr.filter((obj) => originalArr[i] == obj.text)[0]
let node = filteredObj.parent
itemSortElement.appendChild(node)
}
}
return {
sortDesc,
sortAsc,
reset
}
})()
you can check it Demo
I don't know how to describe this without making it more complicated.
So look at the result of the code and click on the first link with "Show", then the second one and third one.
When the second link is clicked, first one closes but text remains "Hide" and i want it to change to "Show".
So, when clicking a link, detect if any other link has text "Hide" and change it to "Show".
And please no jQuery...
document.getElementsByClassName("show")[0].onclick = function() {
var x = document.getElementsByClassName("hide")[0];
var y = document.getElementsByClassName("show")[0];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[1].onclick = function() {
var x = document.getElementsByClassName("hide")[1];
var y = document.getElementsByClassName("show")[1];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[2].onclick = function() {
var x = document.getElementsByClassName("hide")[2];
var y = document.getElementsByClassName("show")[2];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
function closeOther() {
var visible = document.querySelectorAll(".visible"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].classList.remove("visible");
}
}
.style {
background-color: yellow;
width: 200px;
height: 200px;
display: inline-block;
}
.hide {
background-color: red;
width: 50px;
height: 50px;
display: none;
position: relative;
top: 50px;
left: 50px;
}
.hide.visible {
display: block;
}
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
I tried to write a solution which didn't use any javascript at all and worked using CSS alone. I couldn't get it to work though - CSS can identify focus but it can't identify blur (ie. when focus has just been removed).
So here is a solution which uses javascript and the classList API, instead:
var divs = document.getElementsByTagName('div');
function toggleFocus() {
for (var i = 0; i < divs.length; i++) {
if (divs[i] === this) continue;
divs[i].classList.add('show');
divs[i].classList.remove('hide');
}
this.classList.toggle('show');
this.classList.toggle('hide');
}
for (let i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', toggleFocus, false);
}
div {
display: inline-block;
position: relative;
width: 140px;
height: 140px;
background-color: rgb(255,255,0);
}
.show::before {
content: 'show';
}
.hide::before {
content: 'hide';
}
div::before {
color: rgb(0,0,255);
text-decoration: underline;
cursor: pointer;
}
.hide::after {
content: '';
position: absolute;
top: 40px;
left: 40px;
width: 50px;
height: 50px;
background-color: rgb(255,0,0);
}
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
Like this?
Just added following to closeOther():
visible = document.querySelectorAll(".show"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].textContent="Show";
}