Event.target works only with first child [duplicate] - javascript

This question already has answers here:
Adding click event listener to elements with the same class
(5 answers)
addEventListener on NodeList [duplicate]
(8 answers)
Closed 4 years ago.
What I want to achieve is a simple tab function.
I have 3 images and a div showTab.
When i click in one of the images, the clicked image should take the active class and show inside showTab div and other image should take inActive class.
I'm totally a newbie in Javascript so forgive me for my ignorance.
For now only the first li inside my ul works.
The others do not show when i click on them.
HTML:
<div class="tab-container">
<div class="showtab active">
</div>
<ul class="tabs">
<li class="tab tab1">
<img src="https://images.unsplash.com/photo-1550364387-ffbad4f8e9b2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt="foto1" class='img'>
</li>
<li class="tab tab2">
<img src="https://images.unsplash.com/photo-1550368759-0fdb22fe8020?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt="foto2" class='img'>
</li>
<li class="tab tab3">
<img src="https://images.unsplash.com/photo-1550371554-387863e7bd38?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" class='img inActive'>
</li>
</ul>
</div>
CSS:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul li{
list-style: none;
}
.showtab{
width: 200px;
height: 100px;
color: red;
font-weight: bold;
display: flex;
margin-bottom: 20px;
}
.showtab img{
width: 100%;
}
.tabs{
display: flex;
}
.tabs li{
display: flex;
cursor: pointer;
width: 100px;
height: 100px;
margin-right: 10px;
}
.tabs li img{
width: 100%;
}
.active{
color: red;
border: 1px solid red;
opacity: 1;
}
.inActive{
color: blue;
border: 1px solid blue;
opacity: .3;
}
JS:
var tabs = document.querySelector('.tabs');
var tab = document.querySelector('.tab');
var showTab = document.querySelector('.showtab');
tab.addEventListener('click', function(event){
event.stopPropagation();
var content = event.currentTarget.innerHTML;
tab.classList.add('active');
showTab.classList.add('active');
showTab.innerHTML = content;
console.log(this);
});
Here is the demo in jsFiddle:

The .querySelector() function only returns the first matching element. You can use .querySelectorAll() instead and then iterate through the returned list:
var tabs = document.querySelectorAll(".tab");
tabs.forEach(tab => {
tab.addEventListener( ... );
});

Related

setAttribute sometimes returns null

I have a simple tabbed gallery which I managed to make with setAttribute.
But sometimes when I click in one of my thumbnails, setAttribute returns "null"
not always but sometimes it does.
And I'm not understanding why is this happening.
I'll appreciate your help.
here is a link to code:
code
and here is my code:
var tabs = document.querySelector('.tabs');
var tab = document.querySelectorAll('.tab');
var showTab = document.querySelector('.showtab');
var img = document.querySelector('.showtabimg');
tab.forEach(thumbNail => {
thumbNail.addEventListener('click', function(item) {
// delete all active or normal elements active class
tab.forEach(i => i.classList.remove('active'));
var content = item.target.getAttribute("src");
this.classList.toggle('active')
img.setAttribute('src', content);
});
});
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul li{
list-style: none;
}
.showtab{
width: 200px;
height: 100px;
color: red;
font-weight: bold;
display: flex;
margin-bottom: 20px;
}
.showtab img{
width: 100%;
}
.tabs{
display: flex;
}
.tabs li{
display: flex;
cursor: pointer;
width: 100px;
height: 100px;
margin-right: 10px;
}
.tabs li img{
width: 100%;
}
.active{
opacity: 1 !important;
}
.inActive{
opacity: .3;
}
<div class="tab-container">
<div class="showtab active">
<img class='showtabimg' src="https://images.unsplash.com/photo-1516308354296-1c9c5b561e0b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="showtabimg">
</div>
<ul class="tabs">
<li class="tab tab1 inActive active">
<img src="https://images.unsplash.com/photo-1516308354296-1c9c5b561e0b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="foto1" class='img '>
</li>
<li class="tab tab2 inActive">
<img src="https://images.unsplash.com/photo-1513346940221-6f673d962e97?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="foto2" class='img'>
</li>
<li class="tab tab3 inActive">
<img src="https://images.unsplash.com/photo-1475489991311-e12f9e89705e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1352&q=80" alt="foto3" class='img'>
</li>
</ul>
</div>
PS:
I have read this but it doesn't answer my question.
document.getElementById sometimes returns null

How to insert background (picture) elements in a bulleted list, a url to which is written in the neighboring bulleted list

There are two bulleted list. One attribute in data-img elements spelledli, url's pictures which should be in the background elements of the second bullet.
I wrote here such code, thinking that he runs across correctly, but it seems with each pass he turns to the first element li
$(".views").each(function() {
var bg = $(this).attr("data-img");
//alert(bg);
$("ol.buttons li a").css({
background: "url(" + bg + ")"
})
})
.views {
display: inline-block;
position: relative;
width: 30%;
height: 50px;
margin: 2px;
background: #ccc;
}
li {
list-style-type: none;
/* Убираем маркеры */
}
li.but {
display: inline-block;
position: relative;
margin: 5px;
width: 50px;
height: 50px;
border-radius: 50%;
border: 1px solid red;
text-align: center;
}
ol.buttons {
text-align: center;
}
a {
background-size: cover!important;
width: 100%;
height: 100%;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<ul class="parent-view">
<li class="views" data-img="http://goodimg.ru/img/tsvetochek-risunok3.jpg"></li>
<li class="views" data-img="http://agu-shop.ru/images/pink_flower_512x512.png"></li>
<li class="views" data-img="http://www.raskraska.ru/counting/flower-bw.gif"></li>
</ul>
<ol class="buttons">
<li class="but"><a>1</a>
</li>
<li class="but"><a>2</a>
</li>
<li class="but"><a>3</a>
</li>
</ol>
I know that even for is, but how it go through I can not understand ...
Try this jsfiddle :
$(".views").each(function() {
var bg = $(this).attr("data-img");
var self = $(this),
index = self.index();
$("ol.buttons li a:eq("+index+")").css(
"background","url(" + bg + ")"
)
})

How do I stop my toggle function at the first and last list items?

I have an unordered list of numbers that scroll.
The selected/middle list item needs to show in a yellow font color.
I have applied a class toggle function to my scroll buttons. I just need help figuring out a solution that will stop the class toggle function when I get to my first and last list item.
The solution I need must allow for the addition and removal of list items without the need to adjust the JavaScript if possible.
As usual, I know this is light work for you guys.
Any and all help is very much appreciated.
HTML
<div id="container">
<div class="box">
<ul id="ulscroller">
<li value="22"> </li>
<li id="1" class="active">1</li>
<li id="2" class="target">2</li>
<li id="3" class="active">3</li>
<li id="4" class="target">4</li>
<li id="5" class="active">5</li>
<li value="21" class="lastitem"> </li>
</ul>
</div>
<!--Button Controls-->
<div class="buttholder">
<a href="#">
<button class="scrollup">UP</button>
</a>
<a href="#">
<button class="buttok">OK</button>
</a>
<a href="#">
<button class="scroll">Down</button>
</a>
</div>
CSS
.box li.target {
color: #fff;
}
.box li.active {
color: #fada15;
}
#container {
position: relative;
width: 310px;
height: 268px;
background: #000;
}
button {
width: 72px;
height: 72px;
margin-top: 5px;
margin-bottom: 5px
}
#container div {
position: absolute;
}
ul li {
font-size: 42px;
color: #fff;
overflow: hidden;
font-family: arial;
text-align: center;
}
li {
list-style-type: none;
margin-bottom: 30px;
margin-top: 32px;
}
.box {
border: 0px #00f solid;
height: 247px;
width: 199px;
overflow: hidden;
}
#container div.buttholder {
position: relative;
float: right;
border: 0px #0f0 solid;
width: 72px;
height: 236px;
top: 11px;
right: 13px;
}
.lastitem {height: 22px;}
JavaScript
$(document).ready(function() {
$('.scroll').click(function() {
$('li').toggleClass('active', 'target');
$('.box').animate({
scrollTop: '+=80'
}, 100);
});
});
$(document).ready(function() {
$('.scrollup').click(function() {
$('li').toggleClass('active', 'target');
$('.box').animate({
scrollTop: '-=80'
}, 100);
});
});
When toggleClass() has two parameters, the second parameter is expected to be a boolean (and not just truthy/falsy).
Therefore, 'target' is ignored in this code:
$('li').toggleClass('active', 'target');
What you could do is set the first li as "active," then move the active class to the previous or next li, depending on which button is pressed.
If the next li is the last child, or the previous li is the first child, then don't move the active class.
Snippet
$(document).ready(function() {
$('.scroll').click(function() {
var current= $('li.active'),
next= current.next().not(':last-child');
if(next.length) {
next.addClass('active');
current.removeClass('active');
}
$('.box').animate({
scrollTop: '+=80'
}, 100);
});
$('.scrollup').click(function() {
var current= $('li.active'),
prev= current.prev().not(':first-child');
if(prev.length) {
prev.addClass('active');
current.removeClass('active');
}
$('.box').animate({
scrollTop: '-=80'
}, 100);
});
});
.box li.target {
color: #fff;
}
.box li.active {
color: #fada15;
}
#container {
position: relative;
width: 310px;
height: 268px;
background: #000;
}
button {
width: 72px;
height: 72px;
margin-top: 5px;
margin-bottom: 5px
}
#container div {
position: absolute;
}
ul li {
font-size: 42px;
color: #fff;
overflow: hidden;
font-family: arial;
text-align: center;
}
li {
list-style-type: none;
margin-bottom: 30px;
margin-top: 32px;
}
.box {
border: 0px #00f solid;
height: 247px;
width: 199px;
overflow: hidden;
}
#container div.buttholder {
position: relative;
float: right;
border: 0px #0f0 solid;
width: 72px;
height: 236px;
top: 11px;
right: 13px;
}
.lastitem {
height: 22px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="box">
<ul id="ulscroller">
<li value="22"> </li>
<li id="1" class="active">1</li>
<li id="2">2</li>
<li id="3">3</li>
<li id="4">4</li>
<li id="5">5</li>
<li value="21" class="lastitem"> </li>
</ul>
</div>
<!--Button Controls-->
<div class="buttholder">
<a href="#">
<button class="scrollup">UP</button>
</a>
<a href="#">
<button class="buttok">OK</button>
</a>
<a href="#">
<button class="scroll">Down</button>
</a>
</div>
There are two solutions:
Solution #1
You can use the .first and .last functions of jQuery:
$('li').not($('li').first()).not($('li').last())
I am choosing all "li" elements,and then remove the first one and the last one.
https://api.jquery.com/last/
Solution #2:
You can also use slice function, like in arrays:
$('li').slice(1,-1)
This will remove the first and last item in the 'li' array of elements.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
Answer of Rick Hitchcock is perfect, however I would just like to add one point.
For every jQuery function you call, you don't need to encapsulate it in a $(document).ready(function() or jQuery(document).ready(function($). A page manipulation begins only when the page has been loaded. So you don't need to check it twice whether the page has been loaded or not.

Add/Remove Class on Scroll

I'm sorry if the question title isn't specific enough... but I really have no idea about the name of the feature I'm aiming here...
Here is the basic stuff at jsfiddle
<style>
body { margin: 0; text-align: center; }
ul { margin: 0; padding: 0; list-style: none; position: fixed; top: 0; width: 100%; display: flex; }
li { flex: 1; padding: 10px; border-bottom: 1px solid black; background: #fff; }
.current { background-color: #eee; }
#content { margin-top: 50px; }
#content > div { padding: 500px 15px; }
#content > div + div { border-top: 1px solid black; }
</style>
<ul id="nav">
<li id="nav-1" class="current">No.1</li>
<li id="nav-2">No.2</li>
<li id="nav-3">No.3</li>
<li id="nav-4">No.4</li>
<li id="nav-5">No.5</li>
</ul>
<div id="content">
<div id="content-1">#01: “First Chapter”</div>
<div id="content-2">#02: “Second Chapter”</div>
<div id="content-3">#03: “Third Chapter”</div>
<div id="content-4">#04: “Fourth Chapter”</div>
<div id="content-5">#05: “Fifth Chapter”</div>
</div>
When the top of the viewport haven't passed #content-2, #nav-1 would have the 'current' class.
When the viewport passed #content-2, #nav-1 would lose the 'current' class and #nav-2 would get the 'current' class.
and so on.
Some of the sites which I've seen using such feature are all using specific scripts, where one would need to made minor changes to the javascript when the number on objects in the content/nav changed.
I'm hoping to know a script where it could handle dynamic number of objects in the content/nav.
Can anyone show me how to do it?
Thank You.
This should be what you're looking for :
Javascript
$(document).ready(function(){
$(window).scroll(function(e){
for (var i = 1; i < $('#nav li').length; i++) {
if($(window).scrollTop() > $('#content-'+i).position().top){
$('#nav li').removeClass('current');
$('#nav-'+i).addClass('current');
}
};
})
});
http://jsfiddle.net/f7fg9t6e/1/
Do not forget to add jQuery to your project ;)

Simple dropdown menu with javascript

I am new at javascript and I can't seem to get this simple dropdown menu to work. This is what I have done so far :
Html code:
<ul>
<li onClick='showMenu()'>
<a href="#" >Birds</a>
<ul class="menu">
<li>Ratites</li>
<li>Fowl</li>
<li>Neoaves</li>
</ul>
</li>
</ul>
CSS code:
a {
color: #06c;
}
ul {
padding: 0;
margin: 0;
background: pink;
float: left;
}
li {
float: left;
display: inline;
position: relative;
width: 150px;
list-style: none;
}
.menu {
position: absolute;
left: 0;
top: 100%;
background: #ccc;
display: none;
}
Javascript code:
function showMenu(){
document.getElementByClass("menu").style.display="block";
}
My javascript code isn't working. Why won't my nested list show when I click?
Here is a jsfiddle link to my code: http://jsfiddle.net/wkmd7h0r/13/
It's getElementsByClassName not getElementByClass. Fixed code:
function showMenu() {
document.getElementsByClassName("menu")[0].style.display = "block";
}
Also getElementsByClassName returns a NodeList collection, so you should use [0] to get the first element in this collection.
Demo: http://jsfiddle.net/wkmd7h0r/14/
Here is an example of more advanced functionality with addEventListener.

Categories