How to add an active class on specific “li” on user click - javascript

I've scoured the web for a straightforward answer and I have not been able to find it. Spent too long trying to figure this out, but I'd appreciate any help or the right direction.
HTML
<ul id="main-li">
<li>item1</li>
<li>item1</li>
<li>item1</li>
</ul>
JavaScript:
document.getElementById('main-li').addEventListener("click", function(e) {
if (e.target && e.target.nodeName === "LI") {
e.target.classList.add("active-class");
}
});
JSFiddle
https://jsfiddle.net/kw0rr3fv/1/
According to David Wash: https://davidwalsh.name/event-delegate
Event delegation allows you to avoid adding event listeners to
specific nodes; instead, the event listener is added to one parent.
That event listener analyzes bubbled events to find a match on child
elements
What is the best way to remove the previous active-class while attaching the class to the selected element?

The only way that exists to remove a class to each child of the UL, is to iterate over them.
If you wish to avoid frameworks like jQuery, you can simply achieve it with a very short code:
document.getElementById('main-li').addEventListener("click", function(e) {
if (e.target && e.target.nodeName === "LI") {
let elements = document.getElementById('main-li').children;
for (let i = 0; i < elements.length; ++i) {
elements[i].classList.remove("active-class");
}
e.target.classList.add("active-class");
}
}, true);
As you see I just added a very short loop to your code that removes the class (it won't block in case the element doesn't have the class).
In the last line of code you may notice I have added a true value: this is the use capture and is used to suggest that UL event must be captured by LI childrens.

I found this to be more challenging than I expected. Is this a common
way to set an active class?
You can use a framework like jQuery which will help you do it faster and in cross-browser fashion.
What is the best way to remove the previous active-class while
attaching it to the selected element?
Check the updated fiddle
document.getElementById('main-li').addEventListener("click", function(e) {
console.log(e);
Array.prototype.slice.call(document.querySelectorAll('#main-li li')).forEach( function( obj ){
obj.classList.remove("active-class");
});
if (e.target && e.target.nodeName === "LI") {
e.target.classList.add("active-class");
}
});
You need to remove the class from all li's first and then go ahead with adding the active-class

I think should be focus only tag "li" and add event listener as my simple code and easy to read below.
var elementsLi = document.querySelectorAll('ul#main-li > li');
for (var i = 0; i < elementsLi.length; i++) {
elementsLi[i].addEventListener('click', function(e) {
// console.log(e.currentTarget); // for see the current element
if (e.currentTarget.classList.contains('active-class')) {
// do something if already have class "active-class"
// remove class or blah blah blah
}
else {
e.currentTarget.classList.add('active-class')
}
});
}
Hope your success :)

Created page which add class "active" on every "li" element click.
<style>
.active { color: red; }
</style>
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<script>
var arr = document.getElementsByTagName("li");
for(var i=0; i<arr.length; i++){
arr[i].addEventListener("click", function(){
for(var j=0; j<document.getElementsByTagName("li").length; j++){
document.getElementsByTagName("li")[j].className = "";
event.target.className = "";
};
event.target.className = "active"
});
}
</script>

You can also use Jquery for this. which is fast and shorter than your code.
$(document).ready(function(){
$('#main-li').on('click',function(){
$(this).addClass('active-class').siblings().removeClass('active-class');
});
});

Related

Select Single DOM Element

I have a eventlistener looking for a click on DOM elements with a certain class, and then changing innerHTML. It works, except it changes the innerHTML on all elements with the same class, and not just the one clicked. Is there a way to limit the scope to the element that was clicked, or do I need to give all the elements their own ID and call them based on IDs?
This is the function that I'm using:
$("button.accordion").click(function(){
if ($(".caretUD").html("▼")) {
$(".caretUD").html("▲");
} else {
console.log("I'm not working...");
}
});
Is that helps ?
this is the current clicked element.
Notice that the event.currentTarget is the element where the event is recorded and this the element who fire the event (can be a child of the event.currentTarget or itself). In your case, with a button, it should be the same.
$("button.accordion").click(function(event) {
if ($(this).html("▼")) {
$(this).html("▲");
} else {
console.log("I'm not working...");
}
});
If .caretUD and button.accordian are both contained with the same container element, what you want is:
$("button.accordion").click(function() {
var caret = $(this).closest(".container").find(".caretUD");
if (caret.html() == "&#9660") {
caret.html("▲");
} else {
console.log("I'm not working");
}
});
Replace .container with the actual class of the element that contains the button and the corresponding caret.
var els = document.getElementsByClassName("button.accordion"); // get all the elements with a certain class
for (var i = 0; i < els.length; i++){
els[i].addEventListener('click',function(e){
e.target.innerHTML = "something"; // e attribute is the key in this solution, as it gets the single DOM element that fired the event
});
}
jQuery solution:
$("button.accordion").click(function(){
if ($(this).html() == "▼") {
$(this).html("▲");
} else {
console.log("I'm not working...");
}
});

Finding the text inside this element

I'm looking to make a fairly simple operation: you click on an li, you get the text inside, using JavaScript (not JQuery). What I can't figure out (or find out) is how to get the innerHTML.
function enable() {
document.addEventListener('click', e => {
if (e.target.classList.contains('refine-menu-li')) {
var selected = this.innerHTML;
console.log('stuff'); // Working
console.log(selected); // Not working
}
});
}
Is the problem that I am using class and so require a for-loop? Or is this a foolish thing to try and use?
Thanks!
You could try something like this, without using an arrow function:
document.getElementById("js-list")
.addEventListener("click",function(e) {
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.innerHTML);
}
});
<ul id="js-list">
<li>value1</li>
<li>value2</li>
<li>value3</li>
</ul>
Arrow functions capture this from the context they are declared in.
this.innerHTML is not the innerHTML you are looking for.
You probably want e.target.innerHTML.
If you weren't using an arrow function, then this will wouldn't be the value you wanted. Event handlers are called in the context of the element they are bound to (document in this case), not the element that triggered the event.
Try this
function enable() {
document.addEventListener('click', e => {
var current = e.target;
if (e.target.classList.contains('refine-menu-li')) {
var selected = current.innerHTML;
console.log('stuff'); // Working
console.log(selected); // Not working
}
});
}
enable();
<ul>
<li class='refine-menu-li a'>1 </li>
<li class='refine-menu-li b '>2</li>
<li class='refine-menu-li c '>3</li>
<li class='refine-menu-li d'>4</li>
</ul>

disable onclick event on div when clicking on inside <a> link (No js framework)

I have this piece of code:
<div id="mydiv" onclick="ajax_call()">
Mylink
</div>
I'd like ajax_call() to be called only when clicking on empty space inside div but not on "Mylink". Is it possible without any external javascript framework?
Moreover I have this piece of css:
div#mydiv:hover{
background-color: blue;
}
Is it possible to disable the :hover stylesheet when the cursor is placed over "Mylink" (in order to suggest that clicking on "Mylink" won't trigger ajax_call() but will take to myurl)?
Attach the function at child element with click event, After clicked on child element it's handler stops the immediate propagation, As a result ajax_call() will not be invoked.
HTML
<div id="mydiv" onclick="ajax_call()">
Mylink
</div>
javaScript
function ajax_call(){
alert("empt space");
}
//this function stops the propagation and not triggered above
//function when clicked on child element.
function notCall(event) {
event.stopImmediatePropagation();
return false;
}
DEMO
I'm not sure what you want but if I keep my imagination may be that this work, lucky !
$("div#mydiv a").hover(function(){
$(this).parent().css("background-color","transparent")
})
Sure, what you need is the event target || scrElement
Like
function ajax_call() {
var target = event.target ? event.target : event.srcElement;
if(target.id==="mydiv") { alert("good to go"); }
}
See : http://jsbin.com/qujuxufo/1/edit
Edit/Update ( missed the second part ) - Started to answer this before the q was closed - but might as well as it now ..
For the second part of the question - it is not possible to set parent elements in CSS ( it flows top to bottom ) - for that some more JS is needed.
See http://jsbin.com/cileqipi/1/edit
CSS
#mydiv:hover { background-color:green; color:#fff}
#mydiv.anchorhover, #mydiv.anchorhover:hover { background-color:white;}
Then JS
var _mydiv = document.getElementById("mydiv");
var _mydiv_anchors = _mydiv.getElementsByTagName("a");
function toggleClass() {
var addClass=true, cls="anchorhover";
if((_mydiv.className).indexOf(cls) >= 0){ addClass=false; }
if(addClass) {
_mydiv.className=_mydiv.className+=' '+cls;
} else {
/* remove */
_mydiv.className=_mydiv.className.replace(new RegExp('(\\s|^)'+cls+'(\\s|$)'),' ').replace(/^\s+|\s+$/g, '');
}
}
for(var i=0, len=_mydiv_anchors.length; i<len; ++i) {
_mydiv_anchors[i].onmouseover = toggleClass;
_mydiv_anchors[i].onmouseout = toggleClass;
}
^ That feels like quite a trip compared to how simple jquery abstracts it .. >
$("#mydiv a").hover(function() {
$(this).parent().addClass("anchorhover");
}, function() {
$(this).parent().removeClass("anchorhover");
});
Either way, the principle is : to add a style class to the parent element on mouseover and remove it on mouseout

onclick event not firing in a for loop

I'm binding (or at least trying to) a function for each li element under a ul.
But the event never fires. Take a look at the code below, the alert saying "foo"
is showing, but the next one saying "bar" is supposed to show once a click
on the li tag is invoked.
function set_search_value()
{
var e = document.getElementById("res_ls");
alert("foo");
for (var i = 0; i < e.children.length; i++)
{
e.children[i].onclick = function() {
alert("bar");
}
}
}
HTML
<ul id="res_ls" class="visible">
<li><span><span class="highlighted">test</span>ing.com</span> <span>(181)</span></li>
</ul>
I dropped your exact code into a jsFiddle and it appears to function as desired: http://jsfiddle.net/qVQU4/
I have one piece of advice to offer, though: Attaching individual click handlers to each <li> element can be problematic for performance reasons in long lists, and also requires extra coding gymnastics if items in the list are being manipulated via javascript on the client side. A better technique would be to attach a single event handler to the parent container, and let the click bubble up to that level.
Here's an example using jQuery: http://jsfiddle.net/qVQU4/1/
$("#res_ls").on("click", "li", function(e) {
// e.target will be set to the <li> element that was clicked
alert("bar");
});
Using the latter technique, any new items added to the list will have their clicks handled automatically, without having to wire any additional event handlers.
Look at this example on the jsFiddle:
http://jsfiddle.net/drfisher/Ts7wZ/
var children = document.getElementById("res_ls").children;
var child;
for (var i = 0, len = children.length; i < len; i++) {
child = children[i];
if (child.nodeType == 1) {
child.onclick = function() {
alert(this.textContent);
}
}
}

No hover event after I used .empty() and .html()

I have a sortable list (jQuery UI) that I want to sort programmatically using the ids of the
"li" elements. (they are all numbers).
To do that, I have made this function:
function resetList()
{
var orderedItems = new Array();
var unorderedItems = $("#sortable").find('li');
for(var i = 0; i < unorderdItems.length; i++)
{
var counter = 0;
var check = false;
do {
if(unorderedItems[counter].id == (i+1))
{
check = true;
orderedItems.push(unorderedItems[counter]);
}
counter++;
} while (!check && counter < unorderedItems.length);
}
$("#sortable").empty().html(orderedItems);
}
I think that works quite well (i am new to javascript, so i don't know if that code is "professional")
The problem is that after I've called the function no jQuery hover or mouseover events are firing anymore (have been working before)
The content of my "li" elements:
<li class="ui-state-default">
<div class="image" style=\"height:100%; width:100%;">
<img class="overlay" src="img/pic.png" height="200" width="200" style="height:200px; width:200px; visibility:hidden;" />
</div>;
</li>
The JavaScript:
$(".image").hover(function(e)
{
//make overlay visible
}, function(e)
{
//hide overlay
});
Any ideas why the hover function does not work after I called resetList()?
Sorry about the bad english and thank you for any help!
-Nick
if you are using jquery 1.7 or higher use .on else use .delegate
$(".image").on("mouseover mouseout",function(evt){
if (evt.type == 'mouseover') {
// do something on mouseover
alert("over");
} else {
// do something on mouseout
alert("out");
}
});
earlier version of jquery
$("body").delegate(".image","hover",function(evt){
if (evt.type == 'mouseenter') {
// do something on mouseover
alert("over");
}else {
// do something on mouseout
alert("out");
}
});
you are right,changed to delegate
Dafen, hover wont work elements that are dynamically created from javascript, hence using .on or delegate, anyways you have found your answer, just correcting my answer so that no one does same mistake i have done.
I'm pretty sure that after you sort your elements, new dom elements get added to your page, replacing the old ones. As a result your event handlers get lost. You should be able to fix it quite easily by using delegated events with on
$(".ui-state-default").on("mouseenter", ".image", function() { .....
$(".ui-state-default").on("mouseleave", ".image", function() { .....
Just to be difficult, integers aren't valid HTML IDs (IDs should start with a letter [A-Za-z])

Categories

Resources