I have some links that will show a div when clicking it. When clicking another link, it should show the link's associated div and hide the previously shown div.
HTML
Text 1
Text 2
Text 3
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
Javascript
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
CSS
.hidden { display: none; }
.unhidden { display: block; }
How can I accomplish this?
Try with:
function unhide(divID) {
var unhidden = document.getElementsByClassName('unhidden');
for (var k in unhidden) {
unhidden[k].className='hidden';
}
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
}
You can do something like this :
function unhide(divID) {
var divs = document.getElementsByTagName('div');
foreach(var div in divs){
div.className = 'hidden';
if(div.id == divID)
div.className = 'unhidden';
}
}
Be careful with document.getElementsByTagName('div');, it will return you all divs on your document. You could adapt it using a wrapper.
For example :
HTML
<div id="wrapper">
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
</div>
JS :
var divs = document.getElementById('wrapper').getElementsByTagName('div');
Try this http://jsfiddle.net/L79H7/1/:
function unhide(divID) {
var divIds = [ "text1", "text2", "text3" ];
for ( var i = 0, len = divIds.length; i < len; i++) {
var item = document.getElementById(divIds[i]);
if (item) {
item.className = divID == divIds[i] ? 'unhidden' : 'hidden';
}
}
}
You could also store in an array the names of the divs you want to hide and iterate over it when unhiding one:
var divs= new Array("text1", "text2", "text3");
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className='unhidden';
}
for (var i in divs){
if (divs[i] != divID){
item = document.getElementById(divs[i]);
if (item) {
item.className='hidden';
}
}
}
}
JSFiddle
You don't need exactly links for this, but if you insist change it to:
<a href="#" onclick='unhide("text3");'>Text 3</a>
Otherwise you can change it to:
<p onclick="unhide('text1')">Text 1</p>
<p onclick="unhide('text2')">Text 2</p>
<p onclick="unhide('text3')">Text 3</p>
<div id="text1" class="unhidden">
This will show up when the Text 1 link is pressed.
</div>
<div id="text2" class="hidden">
This will show up when the Text 2 link is pressed.
</div>
<div id="text3" class="hidden">
This will show up when the Text 3 link is pressed.
</div>
And your function should look like this to add or remove classes:
function unhide(id){
yourElement = document.getElementById(id);
if(yourElement.className == "unhidden"){
yourElement.className = "hidden";
}else{
yourElement.className = "unhidden";
}
}
demo
<div id="text1" class="hidden"> 1 </div>
<div id="text2" class="hidden"> 2 </div>
<div id="text3" class="hidden"> 3 </div>
.hidden{ display:none; }
#text1{ display: block; }
function show(id) {
var item = document.getElementById(id);
var all = document.getElementsByClassName('hidden');
for(var i=0; i<all.length; i++)all[i].style.display = 'none';
if(item)item.style.display = 'block';
}
you can use jquery try the code below and import the jquery library first
$('#text1').show();
$('#text2').hide();
it is the easiest way
Related
I am trying to develop a filter function with includes. As for now, I have 3 main DIV, and each main DIV has its own DIV. The current script I have now only worked on main DIV.
Instead of highlighting main DIV, I only want to highlight matched char DIV.
For example, when key in 'inner', Inner First and Inner Sec will be highlighted. When key in 'Inner First', only DIV for Inner First will be highlighted.
Would appreciate if anyone of you can help me. Thanks in advance.
function myFunction() {
var input = document.getElementById("Search");
var filter = input.value.toLowerCase();
var nodes = document.getElementsByClassName('target');
for (i = 0; i < nodes.length; i++) {
nodes[i].style.backgroundColor = "";
if (input.value !== '') {
if (nodes[i].innerText.toLowerCase().includes(filter)) {
nodes[i].style.backgroundColor = "blue";
for (j = 0; j < nodes[i].length; j++) {
nodes[j].style.backgroundColor = "";
if (input.value !== '') {
if (nodes[j].innerText.toLowerCase().includes(filter)) {
nodes[j].style.backgroundColor = "grey";
for (k = 0; k < nodes[j].length; k++) {
nodes[k].style.backgroundColor = "";
if (input.value !== '') {
if (nodes[k].innerText.toLowerCase().includes(filter)) {
nodes[k].style.backgroundColor = "yellow";
} else {
nodes[k].style.backgroundColor = "red";
}
}
}
} else {
nodes[j].style.backgroundColor = "red";
}
}
}
} else {
nodes[i].style.backgroundColor = "red";
}
}
}
}
<table align="center" width="20%">
<tr>
<td style="padding-right: 10px">
<input type="text" id="Search" title="Type in a name">
<button onclick="myFunction()">
Click to search
</button>
</td>
</tr>
</table>
<br>
<div class="target">
This is my DIV element.
<div class="target">
Inner First
<div class="target">
Inner Sec
</div>
</div>
</div>
<div class="target">
This is another Div element.
</div>
<div class="target">
Can you find me?
</div>
The problem with your code is that node.innerText also gives the text of the child elements. To fix this, you should use node.childNodes[0].nodeValue which will only give the node's text.
Moreover, you are doing nested loops but referencing incorrectly:
for (j = 0; j < nodes[i].length; j++).
nodes[i].length here is undefined. Maybe you mean nodes[i].children.length?
Also, your code is hard to follow with all the nested loops which does the same thing and just differ in color. I suggest you make a recursive function.
Please see below function if I what I'm thinking is correct. I guess you wanted to put different colors depending of the level of the node in the heirarchy. (Open your developer tool to see console.log outputs)
var input;
var filter;
var nodes;
var colors;
function myFunction() {
//initialize variables
input = document.getElementById("Search");
filter = input.value.toLowerCase();
nodes = document.getElementsByClassName('target');
// store colors here for accessing via index
colors = ['blue', 'grey', 'yellow', 'green'];
if (filter !== '') {
updateNodesBg(nodes); //neat
}
}
function updateNodesBg(lNodes, colorIdx) {
colorIdx = colorIdx || 0; // this will be the index of the color
for (var i = 0; i < lNodes.length; i++) {
var currentNode = lNodes[i];
var currentText = currentNode.childNodes[0].nodeValue;
var innerText = currentNode.innerText;
console.log('currentText and innerText EQUAL?', currentText === innerText);
if (currentText.toLowerCase().includes(filter)) {
currentNode.style.backgroundColor = colors[colorIdx]; //pass in the index to get the color
} else {
currentNode.style.backgroundColor = 'red'; //else, we should color red
}
if (currentNode.children && currentNode.children.length > 0) {
updateNodesBg(currentNode.children, colorIdx + 1); //if the node has children, call `updateNodesBg` recursively
}
}
}
<table align="center" width="20%">
<tr>
<td style="padding-right: 10px">
<input type="text" id="Search" title="Type in a name">
<button onclick="myFunction()">
Click to search
</button>
</td>
</tr>
</table>
<br>
<div class="target">
This is my DIV element.
<div class="target">
Inner First 1
<div class="target">
Inner Sec 1
<div>Inner Third 1</div>
</div>
<div class="target">
Inner Sec 2
<div>Inner Third 1</div>
<div>Inner Third 2
<div>Inner Fourth 1</div>
</div>
</div>
</div>
<div class="target">
Inner First 2
<div class="target">
Inner Sec 2
<div>Inner Third 2</div>
</div>
</div>
</div>
<div class="target">
This is another Div element.
</div>
<div class="target">
Can you find me?
</div>
Note that .nodeValue has different returns depending on the type of the node:
Node Value of nodeValue
CDATASection Content of the CDATA section
Comment Content of the comment
Document null
DocumentFragment null
DocumentType null
Element null
NamedNodeMap null
EntityReference null
Notation null
ProcessingInstruction Entire content excluding the target
Text Content of the text node
You need to check if the text is in the current div, then in any child divs.
InnerText and textContent both concatenate text of the parent and all children, so you'll need to figure out where the text is actually coming from.
I do this recursively, because I don't think you'll have that many layers of divs. If there is a lot of nesting, then you'd need to take an iterative approach
function myFunction()
{
let targets = document.querySelectorAll('.target');
targets.forEach(target => target.style.background = 'white');
let filterText = document.getElementById('Search').value;
if(filterText != '')
{
let result = [...targets].filter(target => target.textContent.includes(filterText));
result.forEach(r => { checkSelf(r, filterText); checkKids(r, filterText); });
}
}
function checkSelf(element, filterText)
{
let selfText = element.textContent;
for(let child of element.children)
{
selfText = selfText.replace(child.textContent, '');
}
if(selfText.includes(filterText))
{
element.style.background = 'limegreen';
}
else
{
element.style.background = 'white';
}
}
function checkKids(element, filterText)
{
for(let child of element.children)
{
if(!child.textContent.includes(filterText))
{
child.style.background = 'white';
}
else
{
checkKids(child, filterText);
}
}
}
<table align="center" width="20%">
<tr>
<td style="padding-right: 10px">
<input type="text" id="Search" title="Type in a name">
<button onclick="myFunction()">
Click to search
</button>
</td>
</tr>
</table>
<br>
<div class="target">
This is my DIV element.
<div class="target">
Inner First
<div class="target">
Inner Sec
</div>
</div>
</div>
<div class="target">
This is another Div element.
</div>
<div class="target">
Can you find me?
</div>
I have 4 elements and within onclick() only one of the block div will show;
HTML:
<!--elements that will toggle block div to show-->
<p onclick="expand(this.id)" id="p1"></p>
<p onclick="expand(this.id)" id="p2"></p>
<p onclick="expand(this.id)" id="p3"></p>
<p onclick="expand(this.id)" id="p4"></p>
<!--block div-->
<div id="block_p1"></div>
<div id="block_p2"></div>
<div id="block_p3"></div>
<div id="block_p4"></div>
JS:
function expand(e) {
document.getElementById("block_" + e).style.display = "block";
document.getElementById(e).style.backgroundColor = "#425a94";
}
The problem is when I click the second element after the first, says I click p2 after p1, the block div--block_p1 doesn't disappear as block_p2 is shown, how do I hide the first block after the second is clicked? If I didn't use the parameter I'd do something like this:
function expand() {
document.getElementById("block_p2").style.display = "block";
document.getElementById("p2").style.backgroundColor = "#425a94";
document.getElementById("block_p1").style.display = "none";
}
I don't know how to do the same in the case of the one with a parameter. Also in the case that third element is selected I need to hide the first two blocks as well.
You first need to hide all divs that start with id expanded_, just add this line before rest of your code.
var allExpanded = document.querySelectorAll( "div[id^='expanded_']" );
Array.from( allExpanded ).forEach( s => (s.style.display = "none") );
Your functions becomes
function expand(e)
{
//first hide all
var allExpanded = document.querySelectorAll( "div[id^='expanded_']" );
Array.from( allExpanded ).forEach( s => (s.style.display = "none") );
//then show specific
document.getElementById("expanded_" + e).style.display = "block";
document.getElementById(e).style.backgroundColor = "#425a94";
document.getElementById("toolbar_expand").style.display = "block";
}
From my previous answer, a small amendment to pick up all display elements which can be looped over in the function to remove the class that was previously added:
const buttons = document.querySelectorAll('.button');
const slides = document.querySelectorAll('.slide');
buttons.forEach(button => {
button.addEventListener('click', handleClick, false);
});
function handleClick(e) {
const id = e.target.dataset.id;
slides.forEach(slide => slide.classList.remove('show'));
const slide = document.querySelector(`.slide[data-id="${id}"]`);
slide.classList.add('show');
}
.slide {
display: none;
}
.show {
display: block;
}
<p class="button" data-id="1">icon1</p>
<p class="button" data-id="2">icon2</p>
<p class="button" data-id="3">icon3</p>
<div class="slide" data-id="1">blocki1</div>
<div class="slide" data-id="2">blocki2</div>
<div class="slide" data-id="3">blocki3</div>
You can use the id match selector to get all the div with id having block_ as substring and then hide all of them except the clicked one.
function expand(id) {
document.getElementById('block_'+id).style.display = "block";
document.getElementById(id).style.backgroundColor = "#425a94";
document.querySelectorAll('[id^="block_"]').forEach(function(elem){
if(elem.id !== 'block_'+id){
elem.style.display = "none";
var pId = elem.id.split('_')[1];
document.getElementById(pId).style.backgroundColor = "#fff";
}
});
}
div{
display: none;
}
<!--elements that will toggle block div to show-->
<p onclick="expand(this.id)" id="p1">p1 click</p>
<p onclick="expand(this.id)" id="p2">p2 click</p>
<p onclick="expand(this.id)" id="p3">p3 click</p>
<p onclick="expand(this.id)" id="p4">p4 click</p>
<!--block div-->
<div id="block_p1">P1</div>
<div id="block_p2">P2</div>
<div id="block_p3">P3</div>
<div id="block_p4">P4</div>
Here is the concept of my content being shown/hidden. It also works.
https://jsfiddle.net/mplungjan/a7Lfjsgh/
It works in the small html code above. However, it does not work when I apply it to my larger HTML code. Does someone know why?
My goal is to have many list items with spans attached to the reveal answers button.
HTML:
<nav class="Rightbox" id="RightFrench">
<div id="Stage1">
<h1>Stage 1</h1>
<h5> <span class="HighlightBlue">Exercise 1 - </span></h5>
<h5><button class="AnswerTitle" id="AnswersFrenchStage1Ex1">Reveal Answers</button></h5>
<p class="Task">
<span class="HighlightBlue">Translate the following</span>
</p>
<ul>
<li>
<p> the passeport <textarea></textarea>
<span class="FrenchStage1Ex1">la passeport</span>
</p>
</li>
<li>
<p>the passeport <textarea></textarea>
<span class="FrenchStage1Ex1">la passeport</span>
</p>
</li>
</div>
</nav>
Javascript:
window.onload = function() {
var buttons = document.querySelectorAll(".AnswerTitle");
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() {
var id = this.id.replace(/reveal/, "FrenchStage");
var answers = document.querySelectorAll("." + id);
for (var i = 0; i < answers.length; i++) {
answers[i].style.display = answers[i].style.display == "inline" ? "none" : "inline";
}
}
}
}
CSS:
.Rightbox ul li p span {display:none;}
the problem turns out to be I changed the id of the button, thinking that the javascript was not using the button id. turns out the
var id = this.id.replace(/reveal/, "FrenchStage")
really wanted the button to have an ID containing "reveal"
My HTML
<div class="chapter">text text text </div>
<div class="chapter">text text text </div>
<button id="button">button</button>
My js
var button = document.querySelector('#button');
var chapter = document.querySelectorAll('.chapter');
for(var i = 0; i < chapter.length; i++){
button.addEventListener('click', function(){
for(var i = 0; i < chapter.length; i++) {
chapter[i].classList.add('active');
}
});
}
This adds the class of "active" on clicking the button.
But toggle doesn't work. Instead of
chapter[i].classList.add('active');
When I do,
chapter[i].classList.toggle('active');
the class of "active" does not toggle. console shows no error.
So I tried to check the class of "active" first & remove the class if the class exists. I know I was trying to reinvent the toggle function; as stated above, toggle wasn't working so I tried it anyway.
if (chapter[i].contains('active')){
chapter[i].classList.remove('active');
And I got a slew of error messages. This is as far as I got. I somehow felt that this wasn't going to work but just tried it anyway.
I am stumped.
Can anyone point out why classList.toggle isn't working in my code & how this can be fixed?
Thanks.
You have one too many loop. Remove the outer one:
var button = document.querySelector('#button');
var chapter = document.querySelectorAll('.chapter');
button.addEventListener('click', function(){
for(var i = 0; i < chapter.length; i++) {
chapter[i].classList.toggle('active');
}
});
.active{
color: red;
}
<div class="chapter">text text text </div>
<div class="chapter">text text text </div>
<div class="chapter">text text text </div>
<div class="chapter">text text text </div>
<button id="button">button</button>
var button = document.querySelector('#button');
var chapters = document.querySelectorAll('.chapter');
button.addEventListener('click', function(){
for(var index = 0; index < chapters.length; index++) {
if(chapters[index].classList.contains('active')){
chapters[index].classList.remove('active');
}else{
chapters[index].classList.add('active');
}
}
});
.active {
color: red;
}
<div class="chapter">text text text </div>
<div class="chapter">text text text </div>
<button id="button">Toggle Color</button>
I'd like a code that shows/hides 3 or more text blocks in javascript. I found this solution here Show/Hide On Click but only works with 2 blocks of text.
html:
<a onclick="showText('text1','text2')" href="javascript:void(0);">Show Text 1</a>
<div id="text1" class="hide"> text1 </div>
<a onclick="showText('text2','text1')" href="javascript:void(0);">Show Text 2</a>
<div id="text2" class="hide"> text2 </div>
CSS:
div.hide { display:none; [your properties]; }
div.show { [your properties]; }
Javascript:
function showText(show,hide)
{
document.getElementById(show).className = "show";
document.getElementById(hide).className = "hide";
}
How can I fix it to make it works for 3 of more texts?
For example, this function will show/hide any number of elements by adding necessary classes:
function showText(showElements, hideElements)
{
for (var i=0;i<showElements.length; i++) {
document.getElementById(showElements[i]).className = "show";
}
for (var i=0;i<hideElements.length; i++) {
document.getElementById(hideElements[i]).className = "hide";
}
}
First parameter is an array that contains element ids that you want to show, and second is another array for the ones you want to hide.
Usage:
showText(['id1', 'id2'], ['id3', 'id4']);