Build list when select option change - javascript

I'm trying to display the full list that have the same id that matches with the select option. But I can't figure out how to get the id from the attribute by using the name to be able to filter it.
The html example:
<select id='groopy' onchange='see();'>
<option>default</option>
<option>lista1</option>
<option>list1</option>
</select>
<ul id='grupo'>
<li id='list1' name="lista">Playground (Rangbhoomi)</li>
<li id='default' name="lista">Empire Made Me</li>
<li id='default' name="lista">Transmission</li>
<li id='lista1' name="lista">Hostel Room 131</li>
<li id='default' name="lista">A Disobedient Girl</li>
<li id='default' name="lista">Travels in the Land of Kubilai Khan</li>
<li id='list1' name="lista">The Indian Mutiny</li>
<li id='lista1' name="lista">Beauty and Sadness</li>
<li id='default' name="lista">The Collaborator</li>
<li id='list1' name="lista">I, Lalla</li>
<li id='default' name="lista">No Full Stops in India</li>
<li id='lista1' name="lista">For Lust of Knowing</li>
<li id='default' name="lista">On the Road to Kandahar</li>
</ul>
And the script I'm trying:
<script>
function see(){
var listita = document.getElementById('groopy').options[document.getElementById('groopy').selectedIndex].value;
var items = document.getElementsByName("lista");
var items_id = document.getElementsByName("lista").getAttribute('id');
if(listita==items_id){
for(var i = 0; i < items.length; i++)
{
document.getElementById("description").innerHTML = items[i].outerHTML;
}
}
}
onload= see();
</script>
By the way, the select and the ul are generated dynamically so I don't actually now the id's that could be provided. I'm trying a little different approach here .
When I manage to make the select filter work, the for stop working. WHY? I'm going crazy with this. Please help!!

Firstly you are having multiple elements with same id's which is wrong.. Cause getElementbyId will only fetch the first element encountered by it.
Replace then with class instead
Next you are overwriting the HTML for every iteration, so you will always have the last item appended to it.
Instead store that in a variable and append it after the for loop.
you need to bind your element with a change event, otherwise your call only works once when the page loads for the first time.
Try this
// Cache the selector as you are using it multiple times
var dropdown = document.getElementById('groopy');
function see() {
// set the selected option
var listita = dropdown.options[dropdown.selectedIndex].value
items = document.getElementsByClassName(listita);
html = '';
// For each item with class name, iterate over it and store in a string
for (var i = 0; i < items.length; i++) {
if (items[i].className == listita) {
console.log((items[i].outerHTML));
html += items[i].outerHTML
}
}
// set the html after the for loop
document.getElementById("description").innerHTML = html;
}
onload = see();
// attach the change event handler
dropdown.addEventListener('change', see);
Check Fiddle

try changing the id's to class in the li tags and use this function...
function see(){
var selectedVal = document.getElementById('groopy').options[document.getElementById('groopy').selectedIndex]. value;
var items = document.getElementsByClassName(selectedVal);
var html = '';
for(var i = 0; i < elements.length; i++)
{
html += items[i].outerHTML;
}
document.getElementById("description").innerHTML = html;
}
onload= see();

Step1 - Change id to class
Step2 - Traverse DOM elements with jQuery class selector. In this way replace document.getElementId('id) with $('.className')

Related

Dynamically add class based on page

I have a navagation list written with bootstrap css:
<ul class="nav navbar-nav navbar-right">
<li class="">Home</li>
<li class="">About</li>
</ul>
My question is how can I use javascript to add the class "active" to the "li" tags using javascript? I want it to have the active class on index.html for home and the same for about.html
Is this possible?
JavaScript
var siteList = document.URL.split("/");
var site = siteList[siteList.length - 1];
var list = document.getElementsByTagName("li");
for (var index = 0; index < list.length; index++) {
var item = list[index];
var link = item.firstElementChild;
var href = link ? String(link.href) : "-";
if (href.replace(".html","") === site) {
item.classList.add("open");
} else {
item.classList.remove("open");
}
}
Explanation
You can get the current URL using document.URL, you probably want the just the last part, so you'll have to split it and get the last part, which in your case will be index, about etc.
Then get all the li elements and iterate through them.
If they don't have an a child then ignore it.
If they do get the href attribute and remove the .html at the end.
If that text is the same as the site variable, then that means you should open the element, otherwise close it.
It's not clean, and there's probably a better way to do it, but:
HTML
<ul class="nav navbar-nav navbar-right">
<li id="navIndex" class="">Home</li>
<li id="navAbout" class="">About</li>
</ul>
JS (somewhere)
// Map ids with html page names
var pages = {
navIndex: "index.html",
navAbout: "about.html"
};
// Iterate over map
for(var property in pages) {
// Check to make sure that the property we're iterating on is one we defined
if(pages.hasOwnProperty(property)) {
// indexOf will be 0+ if it appears in the string
if(window.location.href.indexOf(pages[i]) > -1) {
// we can use property because we defined the map to be same as ids
// From https://stackoverflow.com/questions/2739667/add-another-class-to-a-div-with-javascript
var el = document.getElementById(property);
el.className += el.className ? ' active' : 'active';
break; // no need to keep iterating, we're done!
}
}
}
This is more or less a "dirty" approach because it requires more than just JavaScript to get to work (see Nick's answer for a cleaner implementation).
First we set identifiers on our <li> elements, then we map out those identifiers with their respective href attributes.
Once we have the <li>s mapped out, we then iterate over the map's keys (which we set to be the id attributes on our <li>s) and check if the href attribute is present within the site's window.location.href, if it is: add the active class and stop searching, otherwise we keep on trucking.

using loop to check and remove a className from class name string and add another className to the element which triggers the event

it is fairly simple.
I want to make a current class and put it on a link that is currently active
like this : <li class="li current"><a>Link1</a></li>
but before that, the JS should get all of element with class="li", loop through it and remove the class=" current" if any.
after looping end, then add class=" current" to the element which triggers the event.
for example if user clicks on link3 then JS should remove the class=" current" on link1 and then add class=" current" on link3
it would look like this : <li class="li current"><a>link3</a></li>
it looks like I cannot use getElementsByClassName() for event listener. what should I do to make an event listener then?
the HTML
document.addEventListener("DOMContentLoaded",function(){
var et = document.getElementsByClassName("li");
for(i=0; i <et.length; i++){
et[i].addEventListener("click",function(){
funclink(event);
});
};
});
function funclink(event){
//first get all element with class "li" and remove class " current"
//then add class " current" to the element which triggers the event
var slink = document.getElementsByClassName("li");
for(i =0; i < slink.length; i++){
slink[i].className = slink[i].className.replace(" current","");
}
event.currentTarget.className += " current";
}
.current {
color : orange;
}
<ul id="navmenu">
<li class="li current">Home</li>
<li class="li">Call Service
<li class="li"><a class="a-left" href="#">Rental</a></li>
<li class="li"><a class="a-left" href="#">Sales</a></li>
</li>
</ul>
As commented before, you will have to loop over elements to add eventListener. document.getElementsByClassName will return a NodeList.
Also, if you are only calling your function with event param, you can just pass function ref instead.
Also, instead again fetching all lis, just fetch those lis that has class current. This will reduce number of iterations.
You should use classList instead of className. It has many helpful methods like add, remove and toggle.
Edit 1
As you need to retain the selected li even after refresh, you will have to use client storage or query param to tell your JS about the selected element.
For security reasons, SO does not provide access to localStorage, so you will have to copy code and debug on local files.
document.addEventListener("DOMContentLoaded", function() {
var lis = document.getElementsByClassName("li")
for (var i = 0; i < lis.length; i++) {
lis[i].addEventListener("click", funclink.bind(lis[i], i));
}
initializeUI();
});
function funclink(index, event) {
var lis = document.querySelectorAll('.li.current');
for(var i = 0; i< lis.length; i++){
lis[i].classList.remove('current');
}
this.classList.add('current');
setIndex(index)
}
function initializeUI(){
var lis = document.querySelectorAll('.li');
var index = parseInt(locatStorage.getItem('liIndex'));
lis[index || 0].classList.add("current");
}
function setIndex(index){
localStorage.setItem("liIndex", index);
}
function blockAnchors(){
var as = document.querySelectorAll('a');
for(var i = 0; i< as.length; i++){
as[i].onclick = function(){
return false
}
}
}
blockAnchors();
.current{
background: #ddd;
}
<ul id="navmenu">
<li class="li">Home</li>
<li class="li">Call Service
<li class="li"><a class="a-left" href="?module=rental">Rental</a></li>
<li class="li"><a class="a-left" href="?module=sales">Sales</a></li>
</li>
</ul>
Note: I have added a blockAnchors to stop navigation on a's click. This is just for demonstration.
Array of elements doesn't have to initialized two times.
Using li class is a useless. Modern browsers (IE8+) can use querySelector() (querySelectorAll()) (similiar functionality to the jQuery selector).
When document is ready we get array of links in #navmenu, we add listeners to them.
funclink function removes all classes from links and then sets class "current" to the element, that has triggered that function.
var slink; //prepare global scope var that will be filled with link elems
document.addEventListener("DOMContentLoaded", function() {//wait for document to be loaded
slink = document.querySelectorAll("#navmenu li");//fill global var with array of link elems
for (i = 0; i < slink.length; i++) {//add click listener to all link elems
slink[i].addEventListener("click", function() {
funclink(event);
});
}
});
function funclink(event) {
for (i = 0; i < slink.length; i++)slink[i].className = ""; //remove all current classes
event.currentTarget.className = "current"; //add current class to the element that triggered fnc
}
a {
color: blue;
}
.current,
.current a {
color: red;
}
<ul id="navmenu">
<li class="current">Home</li>
<li>Call Service
<li><a class="a-left" href="#?module=rental">Rental</a></li>
<li><a class="a-left" href="#?module=sales">Sales</a></li>
</li>
</ul>

Change link color on hover javascript only

Is it possible to change a certain on hover over another certain item.
For example:
<li>
test
</li>
JS
var list = document.getElementById('li');
var link = document.getElementById('a');
list.onmouseover = function() {
link.style.color = "#8080ff";
}
If i hover over the li item I want the text inside the a tag to change, but this code is not working.
I cant use css or jquery library.
http://jsfiddle.net/Nt8Pq/40/
Your code looks for elements with ids and you have not ids. You would need to select them by the tag name and loop over the collection. And than you would need to find the anchor that is inside of the collection.
var menu = document.getElementById("menu");
var lis = menu.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
var li = lis[i];
li.addEventListener("mouseover", function() {
this.getElementsByTagName("a")[0].style.color = "#8080ff";
});
li.addEventListener("mouseout", function() {
this.getElementsByTagName("a")[0].style.color = "#000000";
});
}
<ul id="menu">
<li>
test
</li>
<li>
test
</li>
<li>
test
</li>
</ul>
In the end this is a lot of code to implement
ul li:hover a {
color : "#8080ff";
}
SO you could just inject a CSS rule if you are not able to actually add styles to the page...
var sheet = window.document.styleSheets[0];
sheet.insertRule('#menu li:hover a { color: #8080ff; }', sheet.cssRules.length);
<ul id="menu">
<li>
test
</li>
<li>
test
</li>
<li>
test
</li>
</ul>
This can be done with some simple HTML event attributes and JavaScript.
<li>
test
</li>
HTML Event Attributes
If you want to do it with JS, here is the answer. But like said before, you shouldn't do it this way:
<li id="list">
<a id="link" href="#">test</a>
</li>
var list = document.getElementById('list');
var link = document.getElementById('link');
http://jsfiddle.net/Nt8Pq/45/
Assuming you can not modify the CSS or the source of the web page, and you are stuck only with a single javascript file in which you wish to modify some features of a web page, then this approach will work:
One caveat is you have to use of an index in document.getElementsByTagName('li') which returns an array. If you always need the first element for example, you can hard code this index as zero. Otherwise, you need to iterate over the collection looking for the one you wish to change.
Finally, you can modify the style of the firstChildElement after you find the list item you want.
var li = document.getElementsByTagName('li')[0];
li.onmouseover = function() {
li.firstElementChild.style.color = "#F00"; // red
}
li.onmouseout = function() {
li.firstElementChild.style.color = "#000"; // black
};
<li>
Mouse over me.
</li>
var nodesArray = document.getElementById('myID').getElementsByTagName('a');
for (var i = 0; i < nodesArray.length; i++) {
nodesArray[i].style.color = 'red';
}
May be you will find your solution in this link:-https://ubuntuforums.org/showthread.php?t=1692280

Adding a class to an element with a specific class

I'm looking for a way to add a class to a certain element with another class.
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li class="hide">Item 4</li>
<li class="hide">Item 5</li>
<ul>
JS/Jquery
if($('li').hasClass('hide')) {
$('li').removeClass('hide').addClass('slide-down');
}
The problem is that the class slide-down gets added to all li elements.
Is there a way to only target the li elements that have the hide class removed?
Mh maybe it's due to the typo in your HTML: class"hide" (you are missing the equal sign).
Also you got a logical error in your code:
if($('li').hasClass('hide')) the condition will yield true if any <li> element in your document has the hide class.
$('li').removeClass('hide').addClass('slide-down'); the first segment $('li') will actually select ALL <li> elements in your document and remove the class hide from them and add the slide-down to ALL <li> elements in your document.
Here's how I'd do it:
$('li.hide').removeClass('hide').addClass('slide-down');
Note that jQuery is about chaining, i.e selecting subsets and applying functions to these subsets.
What this line does is:
$('li.hide') selects all <li> elements in your document which have the hide class - this becomse your "working subset" now.
.removeClass('hide') removes the hide class from this subset we got in the first step and returns the same subset again.
.addClass('slide-down') adds the slide-down class to all <li> in the selected subset returned from step 2, which is the same as from step 1.
JS fiddle: https://jsfiddle.net/q0nzaa7t/
In vanilla JS:
var liHide = document.querySelectorAll('li.hide');
var i;
var length = liHide.length;
for (i=0;i<length;i++) {
liHide[i].className = 'slide-down';
}
Note that, for some reason, querySelectorAll doesn't get updated automatically like document.getElementsByClassName. The same code wouldn't work if we would have used that method for querying the DOM:
var liHide = document.getElementsByClassName('hide');
var i;
var length = liHide.length;
for (i=0;i<length;i++) {
liHide[i].className = 'slide-down'; //<-- this won't update the 2nd element
}
This would have only changed the first element, since liHide[1] becomes liHide[0], because <li class="hide">Item 4</li> is no longer part of HTML Collection.
Plain javascript for the ones with querySelectorAll and classList support:
var items = document.querySelectorAll('li.hide');
for (var i = 0; i < items.length; i++) {
items[i].classList.remove('hide');
items[i].classList.add('slide-down');
}
Without querySelectorAll:
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
if (items[i].classList.contains('hide')) {
items[i].classList.remove('hide');
items[i].classList.add('slide-down');
}
}
Without querySelectorAll and classList:
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
if (new RegExp(/(?:^|\s)hide(?!\S)/g).test(items[i].className)) {
items[i].className = items[i].className.replace(/(?:^|\s)hide(?!\S)/g , '');
items[i].className += ' ' + 'slide-down';
}
}

Count how many UL Elements there are in a Div with Javascript?

I am dynamically adding UL elements to a DIV element. I would like to be able to count how many UL elements there are inside the DIV so that once all the ULs are removed dynamically I can delete the DIV that they are contained in.
<div id="000">
<ul id="000-1">
<li>Stuff</li>
<li>Stuff</li>
</ul>
<ul id="000-2">
<li>Stuff</li>
<li>Stuff</li>
</ul>
</div>
Is there a simple Javascript solution that counts the amount of ULs so that I can do something like this.. ?
if(ulcount == 0){
var remove = document.getElementById("000");
remove.innerHTML = '';
results.parentNode.removeChild("000");
}
Thanks.
#Cheeso's answer is a good pure-JS solution. But, if you're using jQuery, the process can be made simpler.
jQuery('div#000').children('ul').length;
The above code will return the number of child ul elements of the div#000.
To update the count when you add elements dynamically, you will have to create a function and call it to update the number whenever a change occurs:
function countUls() {jQuery('div#000').children('ul').length;}
Bind that to an event so that it will be called when you want to update the number.
Code:
function getDirectChildrenByTagName(elt,tagname) {
var allChildren = elt.children, wantedChildren=[], i, L;
tagname = tagname.toUpperCase();
for(i=0, L=allChildren.length; i<L; i++) {
if (allChildren[i].tagName.toUpperCase() == tagname) {
wantedChildren.push(allChildren[i]);
}
}
return wantedChildren;
}
use it like this:
var zero = document.getElementById("000");
var uls = getDirectChildrenByTagName(zero, 'UL');
var ulCount = uls.length;
....
Try this:
var x = document.getElementById("000-1").querySelectorAll("li").length
console.log(">>>>", x);

Categories