HTML elements are taken from the container. If the parent node has a child, make a button and insert child.id from child in the button. Everything works in the code, but does not want appendChild (h2);
It should look like:
<button id = "parent2"> <h2> child1 </h2> <h2> child2 </h2> </button>
<div id="container">
<div id="parent1"></div>
<div id="parent2">
<div id="child1"></div>
<div id="child2"></div>
<div id="child3"></div>
</div>
</div>
<p id="demo"></p>
var parent = document.getElementById("container").querySelectorAll("*");
for (let i = 0; i < parent.length; i++) {
if(parent[i].hasChildNodes()){
var btn = document.createElement("BUTTON");
btn.id = parent[i].id;
document.getElementById("demo").appendChild(btn);
}
let children = parent[i].childNodes;
for (let i = 0; i < children.length; i++) {
if(children[i]){
var h2 = document.createElement("H2");
h2.innerHTML = children[i].id;
parent[i].appendChild(h2);
}else{}
}
}
There are many mistakes in your code:
This document.getElementById("container").querySelectorAll("*"); does select all children of a container (nested ones too).
You can not nest two loops that iterate over the same variable i.
childNodes does not return only the 3 divs you want, but also all the nodes that represent the spaces/newlines. You need to filter them out, here few possible solutions.
You require h2 tags to be inserted in the button, but you insert them in parent[i]
This should work:
var parent = document
.querySelectorAll("#container > *");
for (let i = 0; i < parent.length; i++) {
if(parent[i].hasChildNodes()) {
var btn = document.createElement("BUTTON");
btn.id = parent[i].id;
document.getElementById("demo").appendChild(btn);
let children = parent[i].childNodes;
for (let j = 0; j < children.length; j++) {
if (children[j].nodeName !== 'DIV') continue;
var h2 = document.createElement("H2");
h2.innerHTML = children[j].id;
btn.appendChild(h2);
}
}
}
<div id="container">
<div id="parent1"></div>
<div id="parent2">
<div id="child1"></div>
<div id="child2"></div>
<div id="child3"></div>
</div>
</div>
<p id="demo"></p>
Related
I am trying to reverse two divs when the client's window is resized, but my function loops.
I know that this can be made very easy using flexbox, but I am more interested in understanding how to make it work using JS. Just got into learning JS and I am experimenting with functions.
when the client's window is below 58em, I want the divs to rearrange - like flex-direction: column-reverse; for example. when the window is not resized or it's size is bigger than 58em, the function should not do anything
var reverse = document.querySelectorAll(".reverse");
function reverseChildren(parent) {
for (var i = 1; i < parent.childNodes.length; i++){
parent.insertBefore(parent.childNodes[i], parent.firstChild);
}
}
window.addEventListener('resize', function () {
if (window.matchMedia("(max-width: 58em)").matches) {
for (i = 0; i < reverse.length; i++) {
reverseChildren(reverse[i]);
}
}
});
<div class=" reverse">
<div class="first">
<h4>some text</h4>
</div>
<div class="second">
<img src='https://images.unsplash.com/photo-1430026996702-608b84ce9281?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=600&h=338&fit=crop&s=363a88755a7b87635641969a8d66f7aa' alt="Registration screen">
</div>
</div>
You should listen for the match media instead of the resize event.
var reverse = document.querySelectorAll(".reverse");
/* Any other code that reverses the ordre of elements is viable within this function */
function reverseChildren(parent) {
let children = [];
for (var i = 0; i < parent.children.length; i++) {
children.push(parent.children[i]);
}
children = children.reverse().map(item => item.outerHTML).join('');
parent.innerHTML = children;
}
let media = window.matchMedia("(max-width: 58em)");
media.addListener(() => {
for (var i = 0; i < reverse.length; i++) {
reverseChildren(reverse[i]);
}
});
<div class=" reverse">
<div class="first">
<h4>some text</h4>
</div>
<div class="second">
<img src='https://images.unsplash.com/photo-1430026996702-608b84ce9281?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=600&h=338&fit=crop&s=363a88755a7b87635641969a8d66f7aa' alt="Registration screen">
</div>
</div>
<span class="mq-value"></span>
I am trying to make it so that when I click on a category, the text, for that category appears. Then when a new category is clicked, the previous category text is removed, and the text for the new category takes its place. Right now, no matter what button I click, all items appear.
index.html
<div class='container'>
<button class="button">Fit guide</button>
<button class="button">Care</button>
<button class="button">Materials</button>
<div class="single-entry">
<p class="fit">lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
<div class="single-entry">
<p>lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
<div class="single-entry">
<p>lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
</div>
index.js
const displayEntryButton = document.querySelectorAll('.button');
const test = document.querySelector('.fit');
for (var j = 0; j < displayEntryButton.length; j++) {
displayEntryButton[j].addEventListener('click', function () {
const allEntries = document.querySelectorAll('.single-entry');
for (let index = 0; index < allEntries.length; index++) {
if(allEntries[index].style.display === 'none') {
allEntries[index].style.display = 'block'
} else {
allEntries[index].style.display = 'none';
}
}
})
}
I've adjusted your code a bit to get things working.
My adjustment primarily adds an id to each entry div and a matching data-value to each button.
The id and data-value are then used for comparison when a button is clicked. If there's a match, the corresponding content is displayed.
Try the snippet below. - Comments are included within the code.
const displayButtons = document.querySelectorAll('.button');
const entryDivs = document.querySelectorAll('.single-entry');
//start for loop to iterate over each button
for (j = 0; j < displayButtons.length; j++) {
//btnValue is declared to capture the data-value attribute
const btnValue = displayButtons[j].getAttribute('data-value');
displayButtons[j].addEventListener('click', function() {
//nested loop to iterate over each entry div
for (i = 0; i < entryDivs.length; i++) {
//entryId is declared to capture the div id
const entryId = entryDivs[i].id;
//if btnValue matches entryId
if (btnValue === entryId) {
//show the corresponding content
entryDivs[i].style.display = "block"
} else {
//otherwise show nothing
entryDivs[i].style.display = "none"
}
}
})
}
/*set all entries to display none by default*/
.single-entry {
display: none;
}
<div class='container'>
<!-- Here we are setting a data-value on each button -->
<!-- The data-value must match the id for each corresponding div -->
<button class="button" data-value="fit">Fit guide</button>
<button class="button" data-value="care">Care</button>
<button class="button" data-value="materials">Materials</button>
<!-- Each div below has an id to match each buttons data-value -->
<div class="single-entry" id="fit">
<p>FIT ENTRY</p>
</div>
<div class="single-entry" id="care">
<p>CARE ENTRY</p>
</div>
<div class="single-entry" id="materials">
<p>MATERIALS ENTRY</p>
</div>
</div>
I have a number of webpages in a report each page has a checbox filter that if selected calls javascript to show hide some elements of the page, the checkbox filter enables to true, all pages are created in advance. The user can traverse from one pages by clocking on a url .
The trouble is because the pages are created in advance the filter always default to true, even if just set to false by user on previous page. I think I need to call some javascript to set the value of the filter to the value of the filter on the calling page but because traversing form page to page via a hyperlink I dont know how to call the Javascript.
FYI
Html Filter
<div class="mb-2">
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="showLabels" id="showLabels" checked="checked" onclick="toggleLabelsFilter('showLabels');">
<label for="showLabels" id="showLabelslabel" class="form-check-label">
Show Labels
</label>
</div>
</div>
Example html that will have elements hidden
<figure class="figure" style="position:relative">
<a href="StatusReport00017_byfolder00021.html">
<img src="../images/E__Melco_TestMusic_WAV_WAV_Antonin Dvorak; Itzhak Perlman, Daniel Barenboim, Samuel Sanders.jpg" class="figure-img" width="200" height="200">
</a>
<div style="position:absolute; top:144px;">
<div class="badge ml-2 badge-primary">
12 files
</div>
</div>
<div style="position:absolute; top:166px;">
<div class="badge ml-2 badge-success">
12 MB
</div>
<div class="badge ml-2 badge-warning">
0 Discogs
</div>
</div>
<figcaption class="figure-caption">
<a href="StatusReport00017_byfolder00021.html">
Antonin Dvorak; Itzhak Perlman, Daniel Barenboim, Samuel Sanders
</a>
</figcaption>
</figure>
Javascript
function toggleLabelsFilter(filterName)
{
var checkbox = document.getElementById(filterName);
if(checkbox.checked)
{
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "visible";
}
}
else
{
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "hidden";
}
}
}
Edit Update
Attempt based on comments
Called when user selects checkbox
function toggleLabelsFilter()
{
var checkbox = document.getElementById("showLabels");
if(checkbox.checked)
{
sessionStorage.setItem("showLabels", true);
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "visible";
}
}
else
{
sessionStorage.setItem("showLabels", false);
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "hidden";
}
}
}
Called when page loaded
function checkFilter()
{
if(sessionStorage.getItem("showLabels")==true)
{
document.getElementById("showLabels").checked=true;
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "visible";
}
}
else
{
document.getElementById("showLabels").checked=false;
var badges = document.getElementsByClassName("badge");
for (i = 0; i < badges.length; i++)
{
badges[i].style.visibility = "hidden";
}
}
}
Whenever I click on a container which is also the h1. But I want to do when I click on the container. I want to make its h1 color blue. Im stuck on the part making the h1 blue.
var container = document.getElementsByClassName('container');
var h1 = document.getElementsByTagName('h1');
// Put event listener on each container
for(var i = 0; i < container.length; i++) {
container[i].addEventListener('click', function() {
// This isn't working
h1[i].style.color = 'blue';
})
}
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
You are referring to the wrong element when you used h1[i].style...
Use this instead and it will work fine. See code below:
var container = document.getElementsByClassName('container');
var h1 = document.getElementsByTagName('h1');
// Put event listener on each container
for(var i = 0; i < container.length; i++) {
container[i].addEventListener('click', function() {
// Get the 1st H1 inside current container
this.getElementsByTagName('h1')[0].style.color = 'blue';
})
}
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
var container = document.getElementsByClassName('container');
var h1 = document.getElementsByTagName('h1');
// Put event listener on each container
for(var i = 0; i < container.length; i++) {
container[i].addEventListener('click', function() {
this.firstElementChild.style.color="blue"
})
}
Inside the container[i].addEventListener('click', ....) this is the HTML Element of the container. Therefore, calling this.firstElementChild will grab the H1 of that container and change it's color to blue. If you add anything before the H1, just call the children function on this and grab the h1 element.
Neither of the answers that have been posted directly address the issue. They rely on changing the entire color of the .container element, or on the <h1> always being the immediate first child of .container.
The problem that you have is that you have is that your i variable is out of scope, and cannot be used inside the event handler you're defining. We can get around this by wrapping the handler function in a closure as follows:
var container = document.getElementsByClassName('container'),
h1 = document.getElementsByTagName('h1');
for(var i = 0; i < container.length; i++)
{
container[i].onclick = (function(i) {return function() {
h1[i].style.color = 'blue';
};})(i);
};
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
<div class="container">
<h1>HELLO</H1>
</div>
Notice that the above will only change the colour of the <h1>. Of course, this assumes that all of your <h1> elements are always matched in number and index by the .container elements (but I assume that they are, from your question).
I need to get all div elements with "display: none" style and then remove all of these elements. Also i need to select just that divs which are contained in #somecontainer element. Have to do it in RAW javascript. Any idea?
example html:
<table id="listtabletemp">
<thead>
<tr id="theader">
<td id="theaderleft">loolz</td>
</tr>
</thead>
<tbody>
<tr class="" rel="13117025">
<td><div><style>
.ikthgjyhtr{display:none}
.tVOx{display:inline}
</style>
<div style="display:none">crap here</div>
<div></div>
<div></div>
<div style="display:none">crap here</div>
<div class="230">something good</div>
<div class="ikthgjyhtr">crap here</div>
<div style="display:none">crap here</div>
<div class="ikthgjyhtr">crap here</div>
<div style="display: inline">something good</div>something good
<div style="display: inline">something good</div>
<div class="21">something good</div>
<div style="display:none">crap here</div>
<div style="display:none">crap here</div>
<div style="display:none">crap here</div>
<div class="4">something good</div>
<div class="224">something good</div></div>
</td>
</tr>
</tbody>
</table>
Simple, the DOM is your friend:
function removeDivs() {
var container = document.getElementById("somecontainer");
var divs = container.getElementsByTagName("div");
var empty = [];
var getStyle = function(obj, css){
var style = null;
if(obj.currentStyle) {
style = obj.currentStyle[css];
} else if(window.getComputedStyle) {
style = window.getComputedStyle(obj, null).getPropertyValue(css);
}
return(style);
};
for(var i = 0, len = divs.length; i < len; i++) {
var div = divs[i];
if(div && ((div.style.display && div.style.display == "none") || getStyle(div, "display") == "none")) {
empty.push(div);
}
}
for(var i = 0, len = empty.length; i < len; i++) {
var div = empty[i];
div.parentNode.removeChild(div);
}
}
Quick and dirty, here's something to get you started:
http://jsfiddle.net/kttsJ/
var parent = document.getElementById('parent');
var items = parent.getElementsByTagName('DIV');
var hidden = [];
for (var i in items){
if ((items[i]).getAttribute !== undefined){
if ((items[i]).hasAttribute('style')){
if ((/display\:\s*none/gi).test(items[i].getAttribute('style'))){
hidden.push(items[i]);
}
}
}
}
for (var i in hidden){
hidden[i].parentNode.removeChild(hidden[i]);
}
This removes divs with the "display: none" style. I tested it on the OP's example. Note: I added a "some-container" id when testing.
function removeDivs() {
"use strict";
//Some container.
const someContainer = document.getElementById("some-container");
//Divs inside it.
const divsInside = someContainer.querySelectorAll("div");
//Loop, remove div if "display: none".
divsInside.forEach(function (divInside) {
const style = window.getComputedStyle(divInside);
if (style.display === "none") {
someContainer.removeChild(divInside);
}
});
}
removeDivs();