I have content that is hidden by default. On button click, I want the selected one to show its content. I.e if find more is clicked on the second div, show the content for that div.
Approach so far:
function showClass(a) {
var e = [];
var e = document.getElementsByClassName(a);
for (elem of e) {
if (!elem) return true;
if (elem.style.display == "none") {
elem.style.display = "block"
} else {
elem.style.display = "none"
}
}
return true;
}
.list {
display: none;
}
a {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="list">
<ul>
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</div>
<div class="list">
<ul>
<li>list 4</li>
<li>list 5</li>
<li>list 6</li>
</ul>
</div>
<div class="list">
<ul>
<li>list 7</li>
<li>list 8</li>
<li>list 9</li>
</ul>
</div>
<a onclick="showClass('list');" class="loadMoreBtn">Find out more</a>
Where am I going wrong?
You have a few issues:
You should use document.getElementsByClassName(a); (note the document)
To iterate through a HTMLCollection (returned by getElementsByClassName) you should use .forEach, for...of or a regular for loop. for...in is not a recommended way to iterate a collection as it is made to iterate over properties in an object. Thus, the for..in loop can give unexpected properties of the HTMLCollection such as its length when using it to iterate (when instead all you're after is the node)
function showClass(a) {
// var e = []; <-- no need for this \/ redeclared below
var e = document.getElementsByClassName(a);
for (elem of e) {
if (!elem) return true;
if (elem.style.display == "none") {
elem.style.display = "block"
} else {
elem.style.display = "none"
}
}
return true;
}
.list {
display: none;
}
a {
cursor: pointer;
}
<div>
<ul class="list">
<p>sample text</p>
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</div>
<div>
<ul class="list">
<li>list 4</li>
<li>list 5</li>
<li>list 6</li>
</ul>
</div>
<div>
<ul class="list">
<p>sample text</p>
<li>list 7</li>
<li>list 8</li>
<li>list 9</li>
</ul>
</div>
<a onclick="showClass('list');" class="loadMoreBtn">Find out more</a>
To have separate buttons for each item/div you can give each item an id, and then toggle the id by passing it through as an argument:
function showClass(id) {
var elem = document.getElementById(id);
var visible = getComputedStyle(elem).display == "block";
if (!visible) {
elem.style.display = "block"
} else {
elem.style.display = "none"
}
}
.list {
display: none;
}
a {
cursor: pointer;
}
<div>
<ul class="list" id="list-one">
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</div>
<div>
<ul class="list" id="list-two">
<li>list 4</li>
<li>list 5</li>
<li>list 6</li>
</ul>
</div>
<div>
<ul class="list" id="list-three">
<li>list 7</li>
<li>list 8</li>
<li>list 9</li>
</ul>
</div>
<a onclick="showClass('list-one');" class="loadMoreBtn">Find out more - Item 1</a>
<br />
<a onclick="showClass('list-two');" class="loadMoreBtn">Find out more - Item 2</a>
<br />
<a onclick="showClass('list-three');" class="loadMoreBtn">Find out more - Item 3</a>
Since you've tagged the question with jQuery and you're including it, you should really use it for this since it's very simple, concise and readable code...
function toggleClass(className) {
$("." + className).toggle();
}
.list {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"> </script>
<div>
<ul class="list">
<p>sample text</p>
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</div>
<div>
<ul class="list">
<li>list 4</li>
<li>list 5</li>
<li>list 6</li>
</ul>
</div>
<div>
<ul class="list">
<p>sample text</p>
<li>list 7</li>
<li>list 8</li>
<li>list 9</li>
</ul>
</div>
<a onclick="toggleClass('list');" class="loadMoreBtn">Find out more</a>
As you can see, jQuery has a toggle() method that toggles visibility, and jQuery methods work on arrays of elements by default, so you don't need a loop and you don't need to check the current visible state of anything.
You could also go a bit further and assign the event handler in Javascript, rather than inline in the anchor element, like this...
$(".loadMoreBtn").on("click", function() {
$(".list").toggle();
});
Keeping your Javascript out of HTML is encouraged, as it means you don't have to hunt different files to find it, which is great for both you and anyone else that ever has to look at your code.
Please have look at below code i have madden few changes in your code
function showClass(a) {
var e = [];
var e = document.getElementsByClassName(a);
console.log(e);
for (i=0;i<=e.length;i++) {
if (!e[i]) return true;
e[i].classList.add("displayblock");
}
return true;
}
function removeClass(a) {
var e = [];
var e = document.getElementsByClassName(a);
console.log(e);
for (i=0;i<= e.length;i++) {
if (!e[i]) return true;
e[i].classList.remove("displayblock");
}
return true;
}
Styles
.list {
display: none;
}
a {
cursor: pointer;
}
.displayblock{
display: block;
}
HTML
<div>
<ul class="list">
<p>sample text</p>
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</div>
<div>
<ul class="list">
<li>list 4</li>
<li>list 5</li>
<li>list 6</li>
</ul>
</div>
<div>
<ul class="list">
<p>sample text</p>
<li>list 7</li>
<li>list 8</li>
<li>list 9</li>
</ul>
</div>
<a onclick="showClass('list');">Find out more</a>
<a onclick="removeClass('list');">Hide more</a>
Share your improve reference
Read the error messsage,
Uncaught ReferenceError: getElementsByClassName is not defined
The actual method you are looking for is window.document.getElementsByClassName
Related
I'm trying to find total character count (offset) from a starting to selected/clicked element/text. For example,
<div>
<span>text 1</span>
<span>text 2</span>
<span>text 3</span>
</div>
if someone clicks on text 2, I need to count total characters of all elements before text 2.
So here is my approach:
(The problem with my code is, it crashes the browser if there are
lots of nested elements, so what could be other efficient way around?)
const root = document.querySelector("#root")
root.addEventListener("click", function() {
const selection = window.getSelection()
const startOffset = selection.getRangeAt(0).startOffset;
const node = selection.getRangeAt(0).startContainer;
const totalOffset = countTotalOffset(node, startOffset);
alert('total offset: ' + totalOffset )
})
function countTotalOffset(node, offset) {
if (!node.previousSibling) {
if (!node.parentElement) return offset;
if (node.parentElement.id === "root") return offset
return countTotalOffset(node.parentElement, offset)
}
const _offset = !node.previousSibling.textContent ? 0 : node.previousSibling.textContent.length;
return countTotalOffset(node.previousSibling, offset + _offset);
}
<h2>Click on any list item to get offset count</h2>
<ul id="root">
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
<li>
list 4
<ul>
<li>list 5</li>
<li>list 6</li>
<li>list 7</li>
<li>list 8
<ul>
<li>list 9</li>
<li>list 10</li>
<li>list 11</li>
<li>list 12
<ul>
<li><span>list 13</span> <span>list 13</span></li>
<li>list 14</li>
<li>list 15
<ul>
<li>list 16</li>
<li><span>list 17</span> <span>list 17</span></li>
<li>list 18</li>
<li>list 19</li>
<li><span>list 20</span> <span>list 20</span></li>
<li>list 21</li>
</ul>
</li>
<li>list 22</li>
<li>list 23</li>
<li>list 24</li>
</ul>
</li>
<li>list 25</li>
<li>list 26</li>
</ul>
</li>
<li>list 27</li>
<li>list 28</li>
</ul>
</li>
<li>list 29</li>
<li>list 30</li>
</ul>
It's not beautiful, but you can try this.
It's about adding a unique placeholder text to your element, then use "innerText" to get all the document text and count everything until you meet the placeholder. The only problem is that it introduces a "magic word".
const root = document.querySelector("#root")
root.addEventListener("click", function() {
const selection = window.getSelection()
const originalText = selection.anchorNode.textContent
const placeholder = "$$$_placeholder_$$$"
selection.anchorNode.textContent = originalText + placeholder
const charsCount = root.innerText.split(placeholder)[0].length
selection.anchorNode.textContent = originalText
alert(charsCount)
})
<ul id="root">
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
<li>
list 4
<ul>
<li>list 5</li>
<li>list 6</li>
<li>list 7</li>
<li>list 8
<ul>
<li>list 9</li>
<li>list 10</li>
<li>list 11</li>
<li>list 12
<ul>
<li><span>list 13</span> <span>list 13</span></li>
<li>list 14</li>
<li>list 15
<ul>
<li>list 16</li>
<li><span>list 17</span> <span>list 17</span></li>
<li>list 18</li>
<li>list 19</li>
<li><span>list 20</span> <span>list 20</span></li>
<li>list 21</li>
</ul>
</li>
<li>list 22</li>
<li>list 23</li>
<li>list 24</li>
</ul>
</li>
<li>list 25</li>
<li>list 26</li>
</ul>
</li>
<li>list 27</li>
<li>list 28</li>
</ul>
</li>
<li>list 29</li>
<li>list 30</li>
</ul>
I have 'n' li elements inside a ul. I want to alert a message only if the li selected/clicked is a multiple of "n"(let it be 3).
In the below example, alert must be shown only if I click the 3rd, 6th and 9th li element:
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
Here, we can use nth-child as well.
$('ul').find('li:nth-child(3n)').click(function(){
console.log($(this).text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
You can use :nth-of-type() selector
$('li:nth-of-type(3n)').click(function() {
console.log('Alert here')
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
You could use the modulo % for this with the help of index() to get the index of the clickd li.
We should add 1 since the index is zero based :
if (($(this).index() + 1) % n == 0) {
//Your logique here
}
Snippet:
var n = $('ul>li').length;
$('li').click(function() {
var currentIndex = $(this).index();
if ( (currentIndex + 1) % n == 0)
{
console.log('Alert here')
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
You can try use this:
var number = 3;
$("ul li").click(function(){
var i = $(this).index() + 1
if(i % number == 0) {
console.log("You clicked on either element 3,6 or 9")
}
})
Demo
var number = 3;
$("ul li").click(function(){
var i = $(this).index() + 1
if(i % number == 0) {
console.log("You clicked on either element 3,6 or 9")
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
Or you can use $(ul li:nth-child(3n)).click() it will take each third element.
Use jQuery index()
UPDATE : Directly running this code should satisfy your requirement. N=3 in this example.
Here is the jsfiddle.
$(document).ready(function(){
var N = 3;
$("ul li").click(function(){
var index = $(this).index() + 1;
if(index%N == 0) {
alert("Is a multiple of "+N);
} else {
alert("Is not a multiple of "+N);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
<li>list item 7</li>
<li>list item 8</li>
<li>list item 9</li>
</ul>
How to wrap all ul elements in div with JQuery automatically?
<div id="my_uls">
<ul>
<li>Item one</li>
<li>Item two
<ul>
<li>Item one of two</li>
</ul>
</li>
</ul>
</div>
But what I want:
<div id="my_uls">
<div>
<ul>
<li>Item one</li>
<li>Item two
<div>
<ul>
<li>Item one of two</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
You need to use .wrap():
$(function() {
$("ul").wrap("<div />");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="my_uls">
<ul>
<li>Item one</li>
<li>Item two
<ul>
<li>Item one of two</li>
</ul>
</li>
</ul>
</div>
Just use wrap function for this
<scrpt>
$(document).ready(function(){
var myuls = $("#my_uls").find("ul");
for(var i=0;i<myuls.length;i++){
$(myuls[i]).wrap("<div></div>");
}
});
</script>
$('#my_uls ul'), This will refer all your ul inside the div.
if you need the 1st ul only
$('#my_uls ul:not(#my_uls ul ul)').
Guys I have a problem in div selection. I have to use lot of dives in my code. but at the same time I have back button at header so i want that back button pressed then I move to back div.
here is my java script code.
<script type="text/javascript">
function toggle_visibility(id) {
var e = document.getElementById(id);
if (e.style.display == 'block') e.style.display = 'none';
else e.style.display = 'block';
hideAllBut(id);
}
function hideAllBut(id) {
var lists = document.querySelectorAll('.list');
for (var i = lists.length; i--;) {
if (lists[i].id != id) {
lists[i].style.display = 'none';
}
}
}
</script>
And Here is my html code example.
<style>
body{
}
#list1 {background-color: coral;}
#list2 {background-color: #45cd2a;}
#list3 {background-color: #ab4d2a;}
</style>
<form action="????" >
<button> Go to back div</button>
</form>
List One
List Two
<input type="button" value="List Four" onclick="toggle_visibility('list3');">
</input>
<div id="list1" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
<div id="list2" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
<div id="list3" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
</body>
</html>
This code works fine but i don't know how to implement a back button to go back div..??
kindly help me.
Try this :
Html :
<body>
<button onclick="back()"> Go to back div</button>
<form action="????" >
</form>
List One
List Two
<input type="button" value="List Four" onclick="toggle_visibility('list3');">
</input>
<div id="list1" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
<div id="list2" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
<div id="list3" class="list" style="display:none;">
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
</body>
jS:
var divHistory=new Array();
function back(){
if(divHistory.length>0){
var id=divHistory.pop();
var curId=document.getElementById(id);
curId.style.display = 'none';
alert(id);;
if(divHistory.length>0){
id=divHistory.pop();
var prevId=document.getElementById(id);
prevId.style.display = 'block';
}
}
}
function toggle_visibility(id) {
var e = document.getElementById(id);
if (e.style.display == 'block') e.style.display = 'none';
else e.style.display = 'block';
hideAllBut(id);
divHistory.push(id);
}
function hideAllBut(id) {
var lists = document.querySelectorAll('.list');
for (var i = lists.length; i--;) {
if (lists[i].id != id) {
lists[i].style.display = 'none';
}
}
}
The code works except it keeps jumping every time I load or refresh the page and I was wondering if anyone knows of a good solution to this? Any help much appreciated.
Press the 'Run' button on this Jsfiddle to see what I mean.
<div id="sideNav_header">Navigation</div>
<ul id="collapsibleMenu">
<li>Link
<ul>
<li>Link</li>
<li>Link</li>
<li>Link</li>
<li>Link</li>
<li>Link</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 2.1</li>
<li>List Item 2.2</li>
<li>List Item 2.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 3.1</li>
<li>List Item 3.2</li>
<li>List Item 3.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 4.1</li>
<li>List Item 4.2</li>
<li>List Item 4.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 5.1</li>
<li>List Item 5.2</li>
<li>List Item 5.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 1.1</li>
<li>List Item 1.2</li>
<li>List Item 1.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 2.1</li>
<li>List Item 2.2</li>
<li>List Item 2.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 3.1</li>
<li>List Item 3.2</li>
<li>List Item 3.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 4.1</li>
<li>List Item 4.2</li>
<li>List Item 4.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 5.1</li>
<li>List Item 5.2</li>
<li>List Item 5.3</li>
</ul>
</li>
<li>Link
<ul>
<li>List Item 5.1</li>
<li>List Item 5.2</li>
<li>List Item 5.3</li>
</ul>
</li>
</ul>
//Script//
$("#collapsibleMenu > li > a").find("+ ul").slideUp(1);
// Expand or collapse:
$("#collapsibleMenu > li > a").click(function() {
$(this).find("+ ul").slideToggle("slow");
});
Yes, change:
$("#collapsibleMenu > li > a").find("+ ul").slideUp(1);
to:
$("#collapsibleMenu > li > a").find("+ ul").slideUp(0);
http://jsfiddle.net/DjbeK/1/
Using slideUp(1) on page load doesn't make sense you can use hide() instead.