Collapsing and Expanding lists in javascript - javascript

I'm using a tutorial to make collapsible lists in HTML.
My HTML looks like this:
<li>
hello
<ul id="node3" style="display:none">
<li>Sub-item 1</li>
<li>Sub-item 2</li>
</ul>
</li>
<li>
test
<ul id="node3" style="display:none">
<li>Sub-item 1</li>
<li>Sub-item 2</li>
</ul>
</li>
node 3,4,5,etc
I'm trying to collapse all these tables using the following JavaScript:
function test2(id, link) {
var e = document.getElementById(id);
if (e.style.display == '') {
e.style.display = 'none';
link.innerHTML = 'Expand';
} else {
e.style.display = '';
link.innerHTML = 'Collapse';
}
}
But when I call the function I'm not too sure what to enter to select all nodes. I still need the individual control on each node, so I can't change all the names to be the same.
Collapse

You could use the class attribute for that.
<li>
hello
<ul id="node1" class="node" style="display:none">
<li>Sub-item 1</li>
<li>Sub-item 2</li>
</ul>
</li>
<li>
test
<ul id="node2" class="node" style="display:none">
<li>Sub-item 1</li>
<li>Sub-item 2</li>
</ul>
</li>
Assuming that you really want to collapse all of them and not toggle their visibility you could write something like this...
function test2(className, link) {
var e = document.getElementsByClassName(className);
for (var i = 0, len = e.length; i < len; i++) {
e[i].style.display = "none";
}
link.innerHTML = "Expand";
}
...and call it like that...
Collapse
Keep in mind that getElementsByClassName does not work in older browsers (< IE9).
UPDATE:
An alternative way of achieving this is by using CSS and changing the class-name of a mutual parent element. Here's a sample CSS code for that:
#mutualParent.hide-nodes li.node {
display: none;
}
Then change your function like this...
function test2(className) {
document.getElementById("mutualParent").className += className;
}
...and call it like that:
Collapse
If you want to toggle the visibility using the test()-function you need to remove the className first or otherwise it stays hidden. Also for this code to work you need to remove the style-attribute from the <ul> tags because style attributes have a higher priority.

Related

How do I show/hide an <li> based on its text content using JavaScript?

I need to hide/show an <li> based on its text content. In the example below, I want to only show the list item that contains "content 1" and hide the rest of the list items. I'm sure there are several ways to do this. Would I need to convert the list to an array and then use the "includes" method, then append style display none/ display block using a conditional statement?
I would have several unordered lists on a page and therefore target them with the wrapper div's ID.
<div id="myDiv">
<ul class="myList">
<li>content 1</li>
<li>content 2</li>
<li>content 3</li>
<li>content 4</li>
</ul>
</div>
As in the subject you ask for a JavaScript solution, here is one. Iterate the li elements involved and set their display style depending on their text content:
for (let li of document.querySelectorAll("#myDiv li")) {
li.style.display = li.textContent === "content 1" ? "" : "none";
}
<div id="myDiv">
<ul class="myList">
<li>content 1</li>
<li>content 2</li>
<li>content 3</li>
<li>content 4</li>
</ul>
</div>
If you want to achieve the text of an element, then you should use
TextContent or innerHtml. textContent is more preferred
because of some security issues and the latest syntax.
You can also use indexOf() method to check if some string in
the element exists or not. It is a string method. A similar syntax
for this one is Node.textContent.indexOf("word") != -1).
Don't forget that you have more than one li tag so you must check
the value of them with a loop(for). Preferably for let foo of
bar.
const li = document.querySelectorAll('li');
document.querySelector('button').addEventListener('click', () => {
for (let x of li) {
if (x.textContent === 'content1') {
x.style.display = 'none';
} else {
x.style.display = 'block';
}
}
});
<ul>
<li>content1</li>
<li>content2</li>
<li>content3</li>
</ul>
<button type="button">Hide</button>
My suggestion:
[...document.querySelectorAll('.myList li')]
.forEach(li => li.style.display = li.innerText === 'content 1' ? 'block' : 'none');
<div id="myDiv">
<ul class="myList">
<li>content 1</li>
<li>content 2</li>
<li>content 3</li>
<li>content 4</li>
</ul>
</div>
Alternatively:
[...document.querySelectorAll('.myList li')]
.forEach(li => {
'content 1' !== li.innerText && (li.style.display = 'none')
});
<div id="myDiv">
<ul class="myList">
<li>content 1</li>
<li>content 2</li>
<li>content 3</li>
<li>content 4</li>
</ul>
</div>

How can I remove and append element li?

My html code like this :
<ul class="list">
<li id="thumb-view-1">view 1</li>
<li id="thumb-view-2">view 2</li>
<li id="thumb-upload-3">upload 3</li>
<li id="thumb-view-4">view 4</li>
<li id="thumb-view-5">view 5</li>
</ul>
<button id="test">Test</button>
My javascript code like this :
<script type="text/javascript">
$('#test').on("click", function(e){
var a = 3;
for(var i = 1; i <= 5; i++) {
if(i == a) {
$('#thumb-upload-'+i).remove();
var res = '<li id="thumb-view-'+i+'">view '+i+'</li>';
$('#thumb-view-'+(i-1)).after(res);
}
}
});
</script>
Demo : https://jsfiddle.net/oscar11/eb114sak/
It works
But my case is dynamic. var a has value between 1 - 5. So var a can have value 1 or 2 or 3 or 4 or 5
While ul tag has 5 li tag. And 5 li tag can have different id type
So in addition to the tag li above, I give an example of another form
Like this :
<ul class="list">
<li id="thumb-upload-1">upload 1</li>
<li id="thumb-view-2">view 2</li>
<li id="thumb-view-3">view 3</li>
<li id="thumb-view-4">view 4</li>
<li id="thumb-view-5">view 5</li>
</ul>
etc
If like that, the result still wrong
It seems it should call the li element based on a
So if a = 3 then the third li tag is deleted and append
But, I'm still confused
How can I do it?
Instead of remove / append, try replaceWith:
$('#test').on("click", function(e){
var a = 3;
for(var i = 1; i <= 5; i++) {
if(i == a) {
var res = '<li id="thumb-view-'+i+'">view '+i+'</li>';
$('#thumb-upload-'+i).replaceWith(res);
}
}
});
This will only replace matching #thumb-upload- elements, so it will handle your dynamic cases.
A simple solution could be to use replaceWith and index as
var index = $( "ul.list" ).index( $("li[id^='thumb-upload']") );
This will get the index of li whose class starts with thumb-upload within your unordered list
$("li[id^='thumb-upload']").replaceWith('<li id="thumb-view-'+index +'">view '+index +'</li>';)
And the above statement will replace that list item with your custom HTML
Another simple solution is to just change the ID as I don't see other changes as
$("li[id^='thumb-upload']").attr('id', $("li[id^='thumb-upload']").attr('id').replace('upload','view'));

How to add a class to an element using jQuery and javascript?

I have the HTML code as given below to add the navigation to my site. (Note that the list is nested)
<div id="navigation">
<ul>
<li>Home</li>
<li>About us</li>
<li>Help</li>
<li>DropDown
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</li>
<li class="last">A Last Link Text</li>
</ul>
</div>
I want to show the currently active page link in new color. So the corresponding list item should have the class active and I use the CSS to change the color. For example, if the default.html is the currently opened page, the code should be <li class=“active”>Home</li>.
How to do that in jQuery and JavaScript (I need both for two different websites).
Can anyone help me?
Thanks for your help.
Get your URL / Parse it:
var pathname = window.location.pathname;
Then add the class:
Jquery:
$(element).addClass('classname');
JS: How do I add a class to a given element?
Try this
$(document).ready(function () {
var url = location.href;
$('#navigation li a').each(function () {
var thisHref = this.getAttribute('href');
if (thisHref !== '#' && url.indexOf(thisHref) !== -1) {
$(this.parentNode).addClass('active');
return;
}
});
});

when second parent menu is clicked show its submenu and hide the submenu of previously clicked parent menu

I have a vertical menu with submenus and I want to show the submenu only if the parent was clicked ,showing only one submenu at a time. But the thing is when other parent menu is clicked its submenu is shown BUT the previous submenu also is seen. How do i hide the previous submenu?? please help . I am new to javascript.
Here is my html-css-javascript code.
<div class="menu">
<ul >
<li>Contacts
<div style="display: none;" id="cert">
<ul >
<li >Submenu 1</li>
<li>submenu 2</li>
</ul>
</div>
</li>
<li>About
<div style="display: none;" id="defect">
<ul >
<li>menu 1</li>
<li>menu 2</li>
</ul>
</div>
</li>
</ul>
script
function Myfunction(obj) {
var ele=document.getElementById(obj).style;
if(ele.display=="none") {
ele.display="block";
} else { ele.display="none"; }
}
The easiest way will be using a global JavaScript variable, although it's not very elegant. Since you're not using any JavaScript libraries like e.g. jQuery everything else will turn into a pile of DOM-traversing spaghetti code.
var openEle = null;
function Myfunction(obj) {
var ele = document.getElementById(obj);
if (openEle != null) {
openEle.style.display = "none");
}
if (ele.style.display == "none") {
openEle = ele;
ele.style.display = "block";
} else {
ele.style.display = "none";
}
}
<a class="Label">Contacts</a>
<div>
<ul class="Submenu">
<li>Menu 1</li>
<li>Menu 2</li>
</ul>
</div>
<a class="Label">About</a>
<div>
<ul class="Submenu">
<li>Menu 1</li>
<li>Menu 2</li>
</ul>
</div>
And :
(function($) {
$(function() {
$('.Label').on('click', function() {
$('.Submenu').hide();
$(this).next().find('.Submenu').show();
});
});
})(jQuery);
That's the jQuery approach. I'll let another couragous guy do it with native js :D
You can use this:
Demo here
var lastid;
function Myfunction(obj) {
var ele = document.getElementById(obj).style;
var elemLastId = document.getElementById(lastid);
if (elemLastId != null) {
elemLastId.style.display = "none";
}
lastid = obj;
if (ele.display == "none") {
ele.display = "block";
} else {
ele.display = "none";
}
}
I made a new variable to remember the last ID. So you can call it and apply display:none to it.

PrototypeJS: Selecting the odd subset of visible children

This is related to my previous question about selecting visible elements. Now, here's the twist: Let's say I want to select the odd children only from the set of visible children of an element. What would be the best way to do this?
Edit: here is an example of my input and expected output.
<!-- A list with some visible and invisible children -->
<ul class="stripe">
<li>Visible 1</li>
<li style="display:none;">Visible 2</li>
<li style="display:none;">Visible 3</li>
<li>Visible 4</li>
<li style="display:none;">Visible 5</li>
<li>Visible 6</li>
<li>Visible 7</li>
</ul>
<!-- Only the visible children. -->
<li>Visible 1</li>
<li>Visible 4</li>
<li>Visible 6</li>
<li>Visible 7</li>
<!-- The "odd" visible children. -->
<li>Visible 1</li>
<li>Visible 6</li>
I came up with two ways. One works, but the other doesn't.
// Method one: Returns the odd children whether they are visible or not. :(
var listChildren = $$("ul.stripe > li");
var oddChildren = allChildren
.findAll(function(el) { return el.visible(); })
.findAll(function(el) { return el.match("li:nth-child(odd)"); });
oddChildren.invoke("addClassName", "odd");
What I am currently doing now is the following:
// Method two: grouping!
var listChildren = $$("ul.stripe > li");
var oddChildren = listChildren
.findAll(function(el) { return el.visible(); })
.eachSlice(2, function(el) {
el[0].addClassName("odd");
});
This code seems like it could be improved. Can anyone suggest a better way to accomplish this?
The CSS select won't work for the application you desire, it doesn't work correctly on an Array outside of the context of the DOM.
You can do this as follows:
var index = 0;
var myChildren = $$("ul.stripe > li")
.select(function(e) { return e.visible(); })
.select(function(e) {return ++index % 2 == 1; });
Can't you merge the two conditions like this?
var listChildren = $$("ul.stripe > li");
var oddChildren = allChildren
.findAll(function(el) { return el.visible() && el.match("li:nth-child(odd)"); })
oddChildren.invoke("addClassName", "odd");

Categories

Resources