apply effects to specific lis using plain javascript - javascript

I can do this in jquery but for some reason my boss prefers cutting the server request down to 32kb than using the magic of jquery. So, How can I apply effects to all li tags on click using plain javascript?
I have tried getElementById but this only works on ids. not very good with javascript as well. My li is so basic, it doesn't have class name.
EDIT:
Want to hide all li on click. Tried this from one of the answers but error saying
TypeError: document.getElementById(...).getElementsByTagName(...).style is undefined
document.getElementById('holder').getElementsByTagName('li').style.display="none‌​";
many thanks.

Use document.getElementsByTagName('li'); this will return all li-s. Or get li s from specific element:
document.getElementById('myelementid').getElementsByTagName('li');
EDIT hiding all li elements inside element with id- "holder":
var lis = document.getElementById('holder').getElementsByTagName('li');
for(var i = 0; i < lis.length; i++){
lis[i].style.display="none‌​";
}

Try this:
var allLis = document.getElementsByTagName('li'), thisLi, i, l;
for(i=0, l=allLis.length; i<l; i++){
thisLi = allLis[i];
// do something to 'thisLi' here
}

Related

Hide nav when clicking on anchor tags (Vanilla JavaScript)

I have a nav which is displayed on small screens. My goal is to hide that nav each time the anchor tags in it are clicked.
I've tried multiple options until now, but none of them seem to work. I think the real problem here is that I don't know how to select all the anchor tags in the menu. The solution that I'm looking has to be pure JS. Thank you in advance.
<nav id="mySidenav" class="sidenav">
About
Services
Contact
</nav>
.sidenav {
width: 0;
}
.sidenav.mobile-only {
width:250px;
}
function closeNav() {
myNav.classList.remove("mobile-only");
}
Option 1
var anchorTags = document.querySelectorAll('a')
anchorTags.addEventListener('click', closeNav(), false);
** Uncaught TypeError: anchorTags.addEventListener is not a function
Option 2
var anchorTags = document.getElementsByTagName("a")
anchorTags.addEventListener('click', closeNav());
**Uncaught TypeError: anchorTags.addEventListener is not a function
Option 3
var anchorTags = document.querySelector("mobile-only a");
for (var x = 0; x < anchorTags.length; x++) {
anchorTags[x].addEventListener("click", function() {
closeNav();
});
};
**Uncaught TypeError: Cannot read property 'length' of null
The only solution that I've found was to add the function inline, but I'm sure there has to be a better solution.
About
Services
Portofolio
Later edit:
Option 4: The winner (there are better solutions than this which are listed bellow. Thanks everyone)
var anchorTags = document.getElementById("mySidenav").childNodes;
for (var x = 0; x < anchorTags.length; x++) {
anchorTags[x].addEventListener("click", function() {
closeNav();
});
};
Thank you everyone for your responses, I finally understood what the problem was. I've tried all your solutions and they work perfectly.
We're going to go with Option 3 since it is closet to the solution.
You should be using document.querySelectorAll('nav a') or even better document.querySelectorAll('.sidenav a'). This will get you a node list of all elements that matched our selector. After that we can use forEach to loop over each node and bind our click event.
document.querySelectorAll('.sidenav a').forEach(function(a) {
a.addEventListener('click', closeNav);
});
Note that I used closeNav instead of closeNav() - the () are important! Using () will try to invoke the function immediately rather than assigning the function as the handler for the event.
In option 1, what returns after running querySelectorAll, is a nodeList which is similar to an array. You can't add an event listener to the list itself, you'll need to add the listener to each item in the list similar to what you've attempted to do in option 3. In option 2, it is the same problem, but this time with an HTMLCollection. In option 3, you've done querySelector rather than querySelectorAll which only returns the first element that matches the selector. so if you try option 3 with querySelectorAll, it should work.
When you use getElementsByTagName what it returns is a Node collection, not a HTMLElement, therefore you need to loop it to add to each element the event listener
var anchorTags = document.getElementsByTagName("a");
[...anchorTags].map(elem => elem.addEventListener('click', closeNav));
Same thing with querySelector, it returns a HTMLElement (only one) and if you want them all use querySelectorAll, you need to pass it a CSS Selector
var anchorTags = document.querySelector("a.mobile-only");
[...anchorTags].map(elem => elem.addEventListener('click', closeNav));
I used array spread [...arraish_element] to give to the Node Collection all the methods of a true array and being able to use map there, or you can just use a for with the length of the nodecollection

Count hidden next-line items in a list

I have a list with inline list-items. I can see about 8 but then there is not enough space to show more and the rest appears on the next line, hidden (behind the container's z-index) because of its overflow:hidden. How can I count these next line items with JavaScript?
I know jQuery has $('li:visible') but I need a vanilla JavaScript way.
I've tried to leverage getComputedStyle(el) but there doesn't seem to be any way to target these hidden items.
There is also a complicated Page Visibility API but I don't think it can be used for elements, only the document visibility.
Here's a JSFiddle of the list items
For your situation, you need to id if the top of the LI is "under the fold" of the UL. For this we can use element.getBoundingClientRect():
function isVis(elm){
var box = elm.getBoundingClientRect(),
par = elm.parentNode.getBoundingClientRect();
return par.bottom-par.top>= box.top;
}
Live demo:
https://jsfiddle.net/ntcsh18g/
note this is NOT a general purpose "is the element hidden" routine, which is complicated and slow, rather its a simple check against the OP's property that's causing "hiddennes"...
Edit: As suggested by #dandavis, my solution was not generic at all (only works for one row of elements), so only use this in extremely specific and simple cases! To generalize this approach you could try and check whether the offsetTop of an element is greater than the height of the container or the offsetLeft is bigger than the width. Anyway, you are probably better off using his solution anyway. ;)
Well, depending on what you need this for, a very ugly, but working solution could be to check for elements that have a different offsetTop than the first element like this:
const children = [...document.querySelectorAll('#container li')]
const normalOffset = children[0].offsetTop
const overflownChildren = children.filter(li => li.offsetTop !== normalOffset)
https://jsfiddle.net/Isti115/nc3tahw3/
You'll need to target the ul element and save that into a variable var lists = document.getElementsByTagName("ul"); Then use for-loop something like below
<ul id="foo">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
var lists = document.getElementsByTagName("ul");
for (var i = 0; i < lists.length; ++i) {
// filter so that only lists with the class "foo" are counted
if (/(^|\\s)foo(\\s|$)/.test(lists[i].className)) {
var items = lists[i].getElementsByTagName("li");
for (var j = 0; j < items.length; ++j) {
// do something with items[j]
}
}
}

Find all specific element in dom and add class on next element

Im trying to find all img in a page and if the next tag is div.txt add class test on this next element.
I've tried this but I dont know why it isnt working:
for(i = 0; i < $('.page img').length; i++){
$('.page').find('img:eq('+i+')').next('.txt').addClass('teste');
}
Some help would be appreciated.
You were missing $. No need to loop, use .each() like this:
$('.page img').each(function(){
$(this).next('.txt').addClass('teste');
});

JS select child of this with specific class

I am writing a GreaseMonkey script that goes through a page with various elements and each element has text and a button. It uses document.getElementsByClassName to find the parent elements, and it has a for loop to do something to each parent element. In this loop, I need to select a child node with a specific class and find its text value (innerHTML). I can't figure out how to select the child with a specific class of this element.
You'll want to grab the currently iterated element and use querySelector()
For example:
var elements = document.getElementsByClassName('class');
for (var i = 0, len = elements.length; i < len; i++) {
var child = elements[i].querySelector('.class_of_desired_element');
//do stuff with child
}
Note the dot before the class name in querySelector as it works similar to jQuery.
Try querySelectorAll(), which you can use to find elements within the current element.
var parent = document.getElementsByClassName('parentClass'),
parent[0].querySelectorAll('.childClass');
Depending on exactly what you are looking to do, you could also skip selecting the parent, if you don't explicitly need a reference to it.
document.querySelectorAll('.parentClass .childClass');
https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll
You can use
var yourelement = document.getElementsByClass("");
var i = yourelement.nextSibling;
var e = i.nextSibling;
and keep getting the nextSibling of the element till you get it.
However, like #teddy said in the comments, I would suggest you use jQuery. It has a MUCH easier way to do it:
var value = $('.parentClass .childClass').html();

using document.getElementsByTagName doesn't find elements added dynamically (IE6)

I am trying to write a method that grabs all the elements of a certain classname for browsers that don't have the 'getElementsByClassName' method. This works perfectly for elements that are generated server-side, however the page has the ability to add elements dynamically for some reason 'window.document.all' does not get these dynamic elements. Any ideas? Method below.
function getClassName(class) {
var i, neededStuff = [], elements = document.getElementsByTagName('*');
for (i = 0; i < elements.length; i++) {
if (elements[i].className == class) {
neededStuff[neededStuff.length] = elements[i];
}
}
return neededStuff;
}
class is a reserved keyword in IE. Don't use it literally. Change class to something like theClass.
Also, try document.getElementsByTagName('*') instead of document.all if changing class doesn't do it.
EDIT:
http://work.arounds.org/sandbox/72
Works perfectly for me in IE6 ^
Let me try dynamically adding...
EDIT #2: works fine..
http://work.arounds.org/sandbox/72
Use jQuery :)
http://jquery.com/
$('.ClassName')
will return your elements :)
then you can change it's value, add classes very easily!
Some great tutorials here
http://docs.jquery.com/Tutorials

Categories