JS - hide divs after certain count in pure JS - javascript

I have a page where the user can enter as many divs with a specific class they want (filterDiv). I want to have a Load More button display if the number if items is more than nine.
Problem is I am trying to access the divs with class filterDiv after the ninth iteration and add a hide class.
Here is my code:
const htCount = document.querySelectorAll('.filterDiv').length;
if (htCount > 9){
document.querySelector('#loadMore').classList.add('show'); // load more button shows
};
How would I add a code to hide divs 10,11,12 etc. until the Load More button is clicked?

If you have a document with divs that look like this:
<div class=“myDiv”> content </div>
You can first get all the divs:
var myDivs = document.getEmementsByClassName(“myDiv”);
Then loop through them and hide some of them by specifying their style attribute like this:
for(var i = 9; i < myDivs.length; i++) {
myDivs[i].style.display = “none”
}
So we are looping through indexes from 9 till the end of array and making them invisible.
The direct style property of item has higher priority than css of class, so elements will hide and you can specify all the properties of visible elements in css.
Then when a button is clicked, you can do the same loop and just change to .style.display = “block”
for(var i = 9; i < myDivs.length; i++) {
myDivs[i].style.display = “block”
}

Related

Javascript onclick script is changing the class on an element not containing specified class

I have a small piece of javascript to add a css class to a button element that already contains two classes under the top level of a menu when clicking outside that menu.
I understood that writing the two classes as below should select only elements that have both classes. It does what has been asked on the element I specify, BUT, it's also changing the css class of buttons at a lower level.
Here is my code (EDITED as the top line was in my draft but not showing here:)
document.getElementById("myId").addEventListener("click", addClass);
function addClass(event) {
// the click is triggered outside the menu
if(event.target.type != 'button') {
// these are top level buttons only
var buttons = document.getElementsByClassName('btn-level-1 clicked');
for (var i = 0; i < buttons.length; i++) {
buttons[i].classList.add('not-clicked');
buttons[i].classList.remove('clicked'); }
}
}
It's adding the 'not-clicked' class to lower (child) level buttons with the css class 'btn-level-2 clicked' as well.
Also, having added the 'not-clicked' class it does not remove the 'clicked' class.
No jQuery, please. I'm using vanilla JS only.
Thank you.
UPDATE: It works, so please add your answer so I can accept it! Many thanks.
Change your class selector to querySelectorAll.
document.getElementById("myId").addEventListener("click", addClass);
function addClass(event) {
if(event.target.type != 'button') {
var buttons = document.querySelectorAll('.btn-level-1.clicked');
for (var i = 0; i < buttons.length; i++) {
buttons[i].classList.add('not-clicked');
buttons[i].classList.remove('clicked'); }
}
}

Remove class based on elements but not others

I have these sections on this side scrolling site. And want to add a class which will change styling depending if you're on a certain section.
I'm working on this function. The top is what determines the section of the side scroller you are viewing.
The let variables and below is where it stops working. I'm trying to have it so if a nonHome ID section is clicked, for example "slide-1", then add the class 'nav-visibilty'. If they are a match "slide-2" and "slide-2" then remove said class. Am I close?
https://codepen.io/mikayp-the-styleful/pen/NWPxoXR?editors=1111
setTimeout(function(){
for (i=0; i < nonHome.length; i++ ){
if (nonHome[i].id != nonHomeID){
nonHome[i].classList.add("nav-visibility");
console.log('add')
} else{
nonHomeID.classList.remove("nav-visibility");
console.log('rem')
}
}
I am still not totally clear on the behavior that you want, but there are two errors in the code that can be fixed:
It seems like you are always using 'slide-2' instead of the slideId in your event handler.
As mentioned in a comment, nonHomeID is being used incorrectly in your comparison (it is either a string or an element, but you are using it as if it was a string in the if condition, and as the element in the else branch.) Here I have kept it as an element and renamed it for clarity.
Fixing these errors results in code that applies the nav-visibility class to all slides except the one selected by the button. Is that the desired behavior?
let nonHome = document.querySelectorAll(".slide-container section");
let nonHomeSelected = document.getElementById(slideId);
var i;
setTimeout(function() {
for (i = 0; i < nonHome.length; i++) {
if (nonHome[i] != nonHomeSelected) {
nonHome[i].classList.add("nav-visibility");
console.log("add");
} else {
nonHome[i].classList.remove("nav-visibility");
console.log("rem");
}
}
}, 1000);
Edit to add: If the goal is to add nav-visibility to all only the specific slideId, you should not be adding in a loop, i.e. you need to pull your check for whether the slide is Home outside the loop. There are conceptually two steps here: remove the class from all elements that are no longer to have it, then add the class to the element that needs it.
let slideToAddVisibilityTo = document.getElementById(slideId)
let homeSlide = document.getElementById('slide-2')
let allSlides = document.querySelectorAll(".slide-container section")
for (let i = 0; i < allSlides.length; ++i)
allSlides[i].classList.remove('nav-visiblity')
if (slideToAddVisibilityTo != homeSlide)
slideToAddVisibilityTo.classList.add('nav-visibility')
Just hide them all, then show the clicked one:
function showSection(id) {
var sections = document.getElementsByTagName("section");
for(var i=0; i<sections.length; i++) sections[i].classList.remove("nav-visibility");
var current = document.getElementById(id);
current.classList.add("nav-visibility");
}
Example: showSection("foo") will remove nav-visibility from all sections, then add it to the section with id foo.

Show/Hide Elements with multiple attributes by attribute selection (Javascript)

I try to find an easy solution (I am a totally coding beginner, just use javascript in widgets of a "out of the box" page) for the following problem:
There are multiple attributes visitor can select by click Remove/Show
attribute a (Remove/Show)
attribute b (Remove/Show)
attribute c (Remove/Show)
a.s.o.
based on visitors "selection", I would like to show or hide the list of elements:
element 1 (attribute a and b) - Remove if "a" OR "b" has been selected
element 2 (attribute a) - remove if "a" has been selected
element 3 (attribute a and c) - remove, if "a" OR "c" has been selected
a.s.o.
I am able already to hide elements based on a "selection", but in my solution every element show and hide only based on the unique ID (and so also only on the single selection).
The Javascript I found for that is:
<script type="text/javascript">
//<![CDATA[
function swap(openlink,closelink, linkid, dataid)
{
if( document.getElementById(dataid).style.display == 'none')
{
document.getElementById(dataid).style.display='inline';
document.getElementById(linkid).firstChild.nodeValue=closelink;
} else
{
document.getElementById(dataid).style.display='none';
document.getElementById(linkid).firstChild.nodeValue=openlink;
}
}
//]]>
</script>
And than I could use this HTML Code to Remove/Show the elements:
attribute a Remove
attribute b Remove
attribute c Remove
And my element will be Remove/Show by this:
<div id="showmeA" style="display:inline">Element 1</div>
<div id="showmeB" style="display:inline">Element 2</div>
<div id="showmeB" style="display:inline">Element 3</div>
Is there an easy way to add 2 ids to one "element", so that for example Element 1 could be hidden by id=showmeA AND id=showmeB?
You said the issue yourself: IDs are unique.
This is exactly why you should use something else than id, and class attribute is perfectly fine as it does not have to be unique.
Then, this means that the function will not look for your elements using getElementById() but getElementsByClassName().
Note that this function get elements, this involves that you have to loop through these elements and hide / show the ones targeted.
function swap(openlink, closelink, linkid, dataclass) {
var elements = document.getElementsByClassName(dataclass);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if(element.style.display == 'none') {
element.style.display='inline';
document.getElementById(linkid).firstChild.nodeValue=closelink;
} else {
element.style.display='none';
document.getElementById(linkid).firstChild.nodeValue=openlink;
}
}
}
Do not forget to replace id by class attributes to your HTML, you can put in as much as you want, they simply must be separated by a space:
<div class="showmeA showmeB">Element 1</div>
<div class="showmeB">Element 2</div>
<div class="showmeC">Element 3</div>
Here is an example that you can use to better understand the function and attributes used in your solution, this solves your issue: https://jsfiddle.net/sy2mxscf/
It is also important to inform you that inline Javascript is bad, you should reconsider your code when your Javascript skill will increase.
In order to solve the issue pointed out in the comments, you have to use some kind of counter and increment it when you hide the element, decrement it when you show element of one of his class, and displaying the associate element when this counter is 0.
This is also why you need two differentiated links: the "Remove" to increment, and the "Show" to decrement.
There are several way to implement this solution:
Use an associative array in Javascript
Use a custom attribute on the element
Add and remove specific classes
I chose the last one but this may be not the best one, this is just one of the possibilities.
https://jsfiddle.net/sy2mxscf/2/
The idea is to add or remove a custom "hidemeX" class. If you click on two different "Remove" links targeting the same element, two classes will be added. If you then click on any "Show" link, the associate class will be removed. But there is still a "hidemeX" class remaining until you click on the second link, so the element is not displayed thanks to CSS.
As Delgan says, its better to use class here, and you can use those <a>'s id as their class, so when you use your function swap, you can easily trace back to decide if the elements is selected, so the div should be removed.
Below is how you can separate javascript logic and html structure.
var swap = function(e) {
var close = 'Remove', open = 'Show';
var next = this.text === close ? open : close;
// Set the clicked <a>'s text.
this.text = next;
// Get divs that will affect by this <a>
var affectTarget = this.id;
// Affected div elements
var targets = document.getElementsByClassName(affectTarget);
var i, len = targets.length;
var visible;
var watch, wLen, j;
// For each <div> that will be affect by the clicked <a>, we have to chec :
for (i = 0; i < len; ++i) {
// Get the classes that used as a list to show which <a> will have a effect on it.
watch = targets[i].classList;
wLen = watch.length;
// visibilty is default to inline, if no <a> that it watches is selected, then it'll show
visible = "inline";
for (j = 0; j < wLen; ++j) {
// If any of the <a> it watches is selected, set the visibilty to none.
if (document.getElementById(watch[j]).text === open) {
visible = "none";
break;
}
}
targets[i].style.display = visible;
}
};
// For each switcher, we register a click event for it.
var switchers = document.querySelectorAll("a.showSwitcher");
var i, len = switchers.length;
for (i = 0; i < len; ++i) {
switchers[i].addEventListener('click', swap);
}
attribute a Remove
attribute b Remove
attribute c Remove
<hr/>
<div class="swaplinkA swaplinkB" style="display:inline">Element 1</div>
<div class="swaplinkA"style="display:inline">Element 2</div>
<div class="swaplinkA swaplinkC"style="display:inline">Element 3</div>

Why are list elements appearing outside the unordered list?

I have a dynamically added list that gets its values from an object array. However, when looking at the inspector, it shows the list elements after the closing ul tag, but the styles are still applying as though the list elements are inside the ul element. Why is this happening?
HTML
<div id="portfolio_page" class="page">
<aside>
</aside>
</div>
JS
var Portfolio = {
Completed: ["SPARTAN", "Custom Select Menu", "Popup"],
Ongoing: ["Hello"],
Future_Projects: [],
Clients: []
}
for(var key in Portfolio){
var item = key.replace("_", " ");
$("#portfolio_page aside").append("<h1>" +item +"</h1><ul>");
for(var i = 0; i < Portfolio[key].length; i++){
$("#portfolio_page aside").append("<li>" + Portfolio[key][i]+"</li>");
console.log(key[i]);
}
$("#portfolio_page aside").append("</ul>");
}
FIDDLE
You need to create the unordered list first add items to it then append it to the main container ...
$("#portfolio_page aside").append("<h1>" +item +"</h1>");
var $ul = $("<ul></ul>");
for(var i = 0; i < Portfolio[key].length; i++){
$ul.append("<li>" + Portfolio[key][i]+"</li>");
console.log(key[i]);
}
$("#portfolio_page aside").append($ul);
You are getting the elements outside the unordered list because when you were opening it outside the loop [With the closing tag]. The automatically created the ul element [because of the browser attempting to correct the markup closures].
When the list elements were appended it was not being appended to the list [because it was already closed by the browser], but to the main container because it was properly referenced since it was existing before.
Hence, whenever a new container containing individual items need to be appended, make sure you getting a reference to it, add items to it and finally add the element to the main container where you want it to be displayed.
Hope it helps!

Deleting all div children from a parent without a for loop in javascript

I have the following code in my javascript:
for (var a = 0; a < cnt; a++) {
var element = document.getElementById("button" + a).getElementsByTagName("div");
for (index = element.length - 1; index >= 0; index--) {
element[index].parentNode.removeChild(element[index]);
}
$("#button" + a).append("Some large html data");
}
I am deleting all the children from parent id "button0","button1"... and so on, which are divs.
and then appending new data to those parents.
However, this particular piece of code takes a long time to execute when the cnt is more than 200, which it usually is. How will I be able to speed it up? Is there an alternative way to delete all children divs without going through each of it?
<div class="main">
<p>hello p1</p>
<p>hello p2</p>
<span> hello world this is span </span>
</div>
$('.main p').remove(); // any number of depths
$('.main > p').remove(); // immediate children
Try this : You can use children selector to remove them, no need to iterate through children.
for (var a = 0; a < cnt; a++) {
//remove div elements inside button
$("#button"+a+" > div").remove();
$("#button" + a).append("Some large html data");
}
DEMO
IF you can have particular class to button div then you can get rid of for loop.
Lets say class="buttonDiv" is assigned to all button div, for example
<div id="button0" class="buttonDiv">
Now your jQuery script to remove child div will be like
$('div.buttonDiv').each(function(){
$(this).children("div").remove();
$(this).append("Some large html data");
});
DEMO with Class
You can use jQuery to delete them, but I don't know how much faster it will be. Under the covers it has to do pretty much the same work:
for (var a = 0; a < cnt; a++) {
$("#button" + a + " div").remove().end().append("Some large html data");
}
It would be much easier if you just add one class to all the buttons you want to remove the children of. Lets say you add the class button to all of them. Then you could just do this:
$('.button > div').remove(); // Removes all direct children divs of the .button element.
Or
$('.button div').remove(); // Removes all divs inside the `.button` element.

Categories

Resources