How can I trigger onblur from a ul li? - javascript

I am essentially highlighting each li when clicked, and want to "un-highlight" the clicked li when clicking elsewhere or tabbing out (by effecting the background-color property).
This behavior would essentially be emulating <select> in its' highlighting behavior... I'm not using select though, because I want to nest HTML inside the listed items  --  you can't do this with <option>.
I'm attempting to use onblur, which is not working...
Here is the HTML:
<ul id = "list">
<li>asdf</li>
<li>qwerty</li>
<ul>
...here is the CSS:
#list {
list-style-type: none;
}
...and here is the jQuery/Javascript:
function getEventTarget(e) {
e = e || window.event;
return e.target || e.srcElement;
}
function highlightSelection(selection) {
alert("It worked!");
$(selection).css("background-color","#FFFF00");
}
// this function is not being triggered:
function removeHighlight(selection) {
$(selection).css("background-color","none");
}
var ul = document.getElementById("list");
ul.onclick = function(event) {
var target = getEventTarget(event);
highlightSelection(target);
};
// this event is not working:
ul.onblur = function(event) {
var target = getEventTarget(event);
removeHighlight(target);
};

The lis don't blur because they don't focus. Try with mouseout or mouseleave.

Since you're already using JQuery...
<ul id = "list">
<li tabindex="1">asdf</li>
<li tabindex="2">qwerty</li>
<ul>
var ul = $("#list");
ul.on('click focus','li',function(){
$(this)
.css("background-color","#FFFF00")
.siblings().css('background','');
}).on('blur','li',function(){
$(this).css('background','');
});
http://jsfiddle.net/mc4tN/2/
I wasn't sure of what effect you wanted when you tab away from a list item... It seems you would just want to leave it highlighted. You can add focus-ability to your list items by giving them a tabindex attribute.

Related

$(document).on() in plain JavaScript?

In jQuery there is .on() which can be used as:
$(document).on('click', '.foo', function() { /* ... */ });
This listens for click events on all DOM elements with the class .foo.
However, this also listens for any eventual elements added to the DOM later, so it is not equal to:
var elements = document.getElementsByClassName('foo');
for (var element in elements) {
element.addEventListener('click', function() { /* ... */ });
}
How do I do this in plain JavaScript? Am I supposed to use a MutationObserver? If so, then how? If not, then what?
That called event delegation, in the pure javascript you could attach the click event to the parent element then on click check if the clicked element match the target you want to click and perform the action you want ,like the example below :
document.getElementById("parent-item").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was an item with class 'foo'
if(e.target && e.target.className == "foo") {
console.log("foo "+e.target.innerText+" was clicked!");
}
});
Hope this helps.
document.getElementById("parent-item").innerHTML += "<li class='foo'>Item 3</li>";
document.getElementById("parent-item").addEventListener("click", function(e) {
if(e.target && e.target.className == "foo") {
console.log("foo "+e.target.innerText+" was clicked!");
}
});
<ul id="parent-item">
<li class='foo'>Item 1</li>
<li class='foo'>Item 2</li>
</ul>

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

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');
});
});

Pass element as argument when creating event via DOM - JS Javascript

I'm trying to create HTML elements usingn DOM. I need to pass the <li> element to the toogle method as follows:
<ul>
<li onclick="toogle(this)"><a>Some text</a></li>
</ul>
How can I do it?
Current code that doesn't work:
var li = document.createElement("li");
li.onclick = toogle(this);
var li = document.createElement("li");
li.onclick = function () { toogle(this); };
This:
li.onclick = toogle(this);
actually EXECUTES that toogle function, and assigns its return value to the onclick. If you want your function to be called AS the click handler, then it should be
li.onclick = toogle;
The Snippet below demonstrates how to pass an element that was clicked by using event.target. Details are commented in source.
SNIPPET
var li = document.createElement("li");
// Needs to be in DOM before you can click it
document.querySelector('ul').appendChild(li);
// Assigning class for testing
li.className = 'klass';
// Add click event for li
li.addEventListener('click', function(e) {
// event.target is always the element that was clicked
var tgt = e.target;
// Verifying that the li was passed
console.log(tgt.className);
// klass
}, false);
li {
background: #000;
}
<ul></ul>
You can do:
var li = document.createElement("li");
li.addEventListener('click', toogle);
Which will call toogle on click. This is the better way to do it.
and then you can get the element with:
function toogle(e) {
// "e.target" will represent the element
}
Or if you want it your way then you can do:
var li = document.createElement("li");
li.onclick = toogle;
and then you get the element with:
function toogle() {
// "this" will represent the element
}

javascript click event on dropdown menu

an application I have four dropdwon -menu where one of these is filled by selecting an earlier ... this is filled in automatically ... does not respond to click event
I have searching by answers about creating a dinamic UL LI itens and found this:
function getModelos(response)
{
var obj = JSON.parse(response);
try
{
var ul = document.getElementById("modelo");
var modelos = obj.modelos;
var x = document.getElementById("modelo");
while(x.length > 0)
{
x.remove(0);
}
for(i=0;i<modelos.length;i++)
{
var li = document.createElement("li");
var a = document.createElement("a");
a.appendChild(document.createTextNode(modelos[i].modelo));
a.setAttribute("href","#");
a.setAttribute("data-value",modelos[i].id+",.modelo");
li.appendChild(a);
ul.appendChild(li);
}
}
catch(err)
{
alert("ERRO: "+err);
}
}
also I have found a click event delegating:
$(".dropdown-menu li a").click(function()
{
var selText = $(this).text();
$(this).parents('.dropdown').find('.dropdown-toggle').html(selText+' <span class="caret"></span>');
var valor = $(this).data('value');
var options = valor.split(",");
$(this).parents(".dropdown").find(options[1]).val(options[0]);
if(options[1] == ".marca")
{
pedeModelos(selText);
}
});
all dropdowm-menus previously defined response to click on LI, but this dropdown dinamic created don't
I'm new to javascript/Bootstrap/JQuery, I need a way to follow, I will apreciate any help. thanks
Like this:
$(".dropdown-menu").on("click","li a",function() {blah});
Read about Direct and delegated events
The issue is how you are delegating the click event.
If your delegation is outside the event which is creating the dynamic elements than its not going to work. Your reference to the click event should happen in the same function where you are generating the dynamic html.
For example :
<input type="button" id="btn" value="GenerateHTML"/><br/>
<div>
</div>
$("#btn").click(function()
{
$("div").append("<ul class='dropdown-menu'><li><a href='#'>1</a></li><a href='#'>2</a></ul>");
$(".dropdown-menu").find("li a").click(function()
{
alert();
});
});
http://jsfiddle.net/pkhout3x/

why function called more than once onclick event?

<body>
<ul><li onClick="myFunction(this.id)" id="root">Root</li></ul>
<script>
function myFunction(myid) //id of clicked li
{
var id=prompt("Enter Folder id");
if (id != '' && id != null)
{
var val=prompt("Enter Folder name");
}
if (id != '' && id != null && val !='' && val !=null)
{
var ulnode=document.createElement("UL"); //new ul
var node=document.createElement("LI"); //new li
node.setAttribute("id",id);//set id of new li
node.setAttribute("onclick","myFunction(this.id)");//set onclick event of new li
var textnode=document.createTextNode(val);//li value
node.appendChild(textnode);// new li + li value
ulnode.appendChild(node);// new li + li value
document.getElementById(myid).appendChild(ulnode);//old+new
}
}
</script>
</body>
Once you've added a child element, you have something like this:
<ul>
<li onClick="myFunction(this.id)" id="root">
Root
<ul>
<li onClick="myFunction(this.id)" id="abc">
Abc
</li>
</ul>
</li>
</ul>
Since abc is a child of root, clicking abc also clicks root. Sometimes you want this behavior, but not in your case. You can stop events from "propagating" to parent elements by calling the .stopPropagation() method on the event object. The event object is passed to event handlers as an argument.
When you bind event handlers using HTML attributes, the attribute value becomes the handler function body, and the event argument is named event. You can either call event.stopPropagation() in the event handler, or pass the event object to myFunction(). Personally, I'd make myFunction() the handler itself (instead of just a function called by the handler). Change the function to accept an event object for it's argument. When you create the child <li>, rather than setting the onclick attribute, set the onclick property and assign it a reference to myFunction.
function myFunction(e)
{
e.stopPropagation();
var id=prompt("Enter Folder id");
if (id != '' && id != null)
{
var val=prompt("Enter Folder name");
}
if (id != '' && id != null && val !='' && val !=null)
{
var ulnode=document.createElement("UL"); //new ul
var node=document.createElement("LI"); //new li
node.id = id;//set id of new li
node.onclick = myFunction;//set onclick event of new li
var textnode=document.createTextNode(val);//li value
node.appendChild(textnode);// new li + li value
ulnode.appendChild(node);// new li + li value
this.appendChild(ulnode);
}
}
That works for dynamically created list elements. To bind that function to your root element in the HTML, use myFunction.call(this, event):
<ul><li onClick="myFunction.call(this, event)" id="root">Root</li></ul>
Demo
Note that a benefit of this technique is you have a reference to the <li> element in your function, so you don't need to look up the element by id. If that is the only reason you were adding an id to each list item, you can omit that completely. The resulting function is quite a bit shorter:
function myFunction(e)
{
e.stopPropagation();
var val=prompt("Enter Folder name");
if (val)
{
var ulnode=document.createElement("UL"); //new ul
var node=document.createElement("LI"); //new li
node.onclick = myFunction;//set onclick event of new li
node.textContent = val;
ulnode.appendChild(node);// new li + li value
this.appendChild(ulnode);
}
}
Demo
You are dynamically adding <li> elements which might get the same id. If this is the case, this is not allowed. Try to use classes instead and the use of JQuery will be helpful for you. Will shorten the code (at least on your side ;) ) to a minimum.
Use this as a starting point: http://plnkr.co/1apBvS
Also i would separate the button to be in a static place, so you will always see it, even if your <ul> is scrolled because it can get many rows.
Events like click bubble up the DOM (propagate) through all parents
Because you are nesting a child that has parent with same click handler, the event first fires myFunction on the child, then fires on the parent .
You can return false from myFunction to prevent the bubbling
Try wrapping your text inside a <a></a>, like:
<ul>
<li><a onclick="return test()">child</a></li>
</ul>
See this jsfiddle: http://jsfiddle.net/gongzhitaao/k4UEE/3/
I just tried, but I've no idea why <li> with onclick does not work.

Categories

Resources