This is my first foray into using Javascript with HTML. I'm trying to add click events to the list items in an ordered list, but something about the way I'm doing it isn't working. Can somebody shed some light on this for me?
I create a function in my head that should delegate all click events on the list items of a specified list to a given function, and in that given function I try to raise a simple alert with the text of the list item. Eventually I want to do more, but I'm just trying to get the simple click events to work first.
<html>
<head>
<script type="text/javascript">
// Attach an event handler to the 'topfriends' list to handle click events.
function attachEventHandlerToList() {
document.getElementById("#top4list").delegate("li", "click", function(clickEvent) {
alert(this.innerHTML());
});
}
</script>
</head>
<body>
<div id="topfriends">
<h3>Top 4 Most Friendable Friends</h3>
<ol id="top4list" onload="attachEventHandlerToList()">
<li>Brady</li>
<li>Graham</li>
<li>Josh</li>
<li>Sean</li>
</ol>
</div>
</body>
Let's do something like this
<ul id="parent-list">
<li id="a">Item A</li>
<li id="b">Item B</li>
<li id="c">Item C</li>
<li id="d">Item D</li>
<li id="e">Item E</li>
<li id="f">Item F</li>
</ul>
Now write the javascript for this
<script type="text/javascript">
// locate your element and add the Click Event Listener
document.getElementById("parent-list").addEventListener("click",function(e) {
// e.target is our targetted element.
// try doing console.log(e.target.nodeName), it will result LI
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.id + " was clicked");
}
});
</script>
Please refer to this write-up on Javascript Event Delegates
http://davidwalsh.name/event-delegate
Also, below link is the fiddle that I created
http://jsfiddle.net/REtHT/
hope this helps !
delegate() is a deprecated jQuery method, and no such method exists in plain JS.
To attach an event handler in JS you'd use addEventListener, and for older versions of IE you'll need attachEvent as well, that's why it's a little tricky with cross browser event handlers.
onclick, onmouseenter etc. will work in all browsers, but it's consider a better practice to use addEventListener / attachEvent.
Also, you have to run the script after the elements are added to the DOM, otherwise they are not available. The usual way is to insert the script after the elements, or use a DOM ready event handler.
<html>
<head>
<title>test</title>
</head>
<body>
<div id="topfriends">
<h3>Top 4 Most Friendable Friends</h3>
<ol id="top4list">
<li>Brady</li>
<li>Graham</li>
<li>Josh</li>
<li>Sean</li>
</ol>
</div>
<script type="text/javascript">
var lis = document.getElementById("top4list").getElementsByTagName('li');
for (var i=0; i<lis.length; i++) {
lis[i].addEventListener('click', doStuff, false);
}
function doStuff() {
alert( this.innerHTML );
}
</script>
</body>
FIDDLE
Try this. It will work with child Node and Parent Node also.
var visitorList = document.getElementById("visitor");
visitorList.addEventListener("click", function (e) {
var visitorId;
if (e.target && e.target.nodeName == "LI") {
visitorId = e.target.id;
console.log(e.target.id);
}
if(e.target && e.target.nodeName == "H1") {
visitorId = e.srcElement.parentElement.id;
console.log(e.srcElement.parentElement.id);
}
//console.log(visitorId);
});
<ul id="visitor">
<li id="a" style="background: #CCCCCC; padding: 10px;"><h1 style="background: #437ba9;">Visitor A</h1></li>
<li id="b"><h1>Visitor B</h1></li>
<li id="c"><h1>Visitor C</h1></li>
<li id="d"><h1>Visitor D</h1></li>
<li id="e"><h1>Visitor E</h1></li>
<li id="f"><h1>Visitor F</h1></li>
</ul>
You can also do it by using querySelectorAll
<ul class="stuffList">
<li>Stuff 1</li>
<li>Stuff 2</li>
<li>Stuff 3</li>
<li>Stuff 4</li>
<li>Stuff 5</li>
</ul>
<script type="text/javascript">
document.querySelectorAll('ul.stuffList li').forEach((item) => {
item.addEventListener('click', (e) => {
console.log(e.target)
})
});
</script>
Hello why not doing it easier by replacing onLoad directy by onClick
<script type="text/javascript">
function olClicked(){
alert(this.innerHTML());
}
</script>
<ol id="top4list" onClick="olClicked()">
Related
I have an HTML parent-list named "sub-menu" and inside it there is a child list "sub-menu-real".
<li class="sub-menu">HIDE<span class="sub-arrows"></span>
<ul class="sub-menu-real">
<li class="sub-menu-l1">Hide Level 1</li>
<li class="sub-menu-l2">Hide Level 2</li>
<li class="sub-menu-l3">Hide Level 3</li>
<li class="sub-menu-l4">Hide Level 4</li>
</ul>
The problem is that when I use JQuery to define a callback function when the "sub-menu" is clicked, the callback function is called also when I click the children.
Here is the Jquery code:
$(document).ready(function(){
$(".sub-menu").click(function(){
callbackFunction();
});
$(".sub-menu-l1").click(function(){});
$(".sub-menu-l2").click(function(){});
$(".sub-menu-l3").click(function(){});
$(".sub-menu-l4").click(function(){});
Here I just call the callBackFunction inside the .sub-menu class but it is called when I click sub-menu children.
How can I avoid this problem ?
You want to stop event bubbling when triggering a click event on the children.
Something like this:
$(".sub-menu").click(function() {
callbackFunction();
});
$('.sub-menu-l1,.sub-menu-l2,.sub-menu-l3,.sub-menu-l4').click(function(e) {
e.stopPropagation();
});
You have added an EventListener to the wrapping <li> element with the class of sub-menu. As long as your children are wrapped into that element, the click handler will be called by clicking on the element (and those children are part of that element).
So if you want to get rid of this behaviour you need to remove that listener:
$(".sub-menu").click(function(){
callbackFunction();
});
Otherwise every click on an element inside of .sub-menu will call that click handler.
e.stopPropagation() can be used on child elements . Hope this helps
$(".sub-menu").click(function(e){
callbackFunction();
});
$(".sub-menu-real li").click(function(e) {
e.stopPropagation();
});
function callbackFunction()
{
alert(1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<li class="sub-menu">HIDE<span class="sub-arrows"></span>
<ul class="sub-menu-real">
<li class="sub-menu-l1">Hide Level 1</li>
<li class="sub-menu-l2">Hide Level 2</li>
<li class="sub-menu-l3">Hide Level 3</li>
<li class="sub-menu-l4">Hide Level 4</li>
</ul>
Use the a element as trigger for the click event:
$(".sub-menu-click > a").click(function(e){
callbackFunction();
});
What I am trying to do is target all the a tags within #menu-wrap li's.
I'm fairly new to JS so I'm sorry if I'm missing something obvious!
JavaScript:
var menuLink = document.querySelector( '#menu-wrap li' );
for (var i = 0; i < menuLink.children.length; i++) {
var childElement = menuLink.children[i];
childElement.addEventListener('click', doSomething, false);
}
function doSomething() {
alert("Hello");
}
HTML
<div class="menu-wrap" id="menu-wrap">
<nav class="menu">
<ul id="menu-mobile-menu" class="menu">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 1</li>
</ul>
</nav>
</div>
querySelector:
Returns the first element within the document (using depth-first pre-order traversal of the document's nodes|by first element in document markup and iterating through sequential nodes by order of amount of child nodes) that matches the specified group of selectors.
You want to use querySelectorAll and then loop over the resulting node list (or you want to bind your event handler to #menu-wrap itself and then use event.target to determine which list item was clicked on).
List items are not designed to be interactive controls. You should use a link or button instead.
Document.querySelector gets the first element only. But you can do this with classes. Do this. Just attatch class sth to anything you want to have the function.
HTML
<div class="menu-wrap" id="menu-wrap">
<nav class="menu">
<ul id="menu-mobile-menu" class="menu">
<li class="sth">Link 1</li>
<li class="sth">Link 2</li>
<li class="sth">Link 1</li>
</ul>
</nav>
</div>
JS
var menuLink = document.getElementsByClassName("sth");
for(var i = 0; i < menuLink.length; i++ ) {
var childElement = menuLink[i];
childElement.addEventListener('click', doSomething, false);
}
function doSomething() {
alert("Hello");
}
I am currently working on building a small menu that will change divs based upon which one it clicked. So if one is clicked it will show the div associated with it and hide the others, ect. But I cannot get it to work, nor can I figure out why. Any help would be appreciated. Thanks.
Below is my code. I've clipped out the content as there was a lot of it.
<script type="text/javascript">
$('.mopHeader').click(function() {
$('#raid-progress-mop').show();
$('#raid-progress-cata').hide();
$('#raid-progress-wotlk').hide();
$('#raid-progress-tbc').hide();
$('#raid-progress-vanilla').hide();
});
$('.cataHeader').click(function() {
$('#raid-progress-mop').hide();
$('#raid-progress-cata').show();
$('#raid-progress-wotlk').hide();
$('#raid-progress-tbc').hide();
$('#raid-progress-vanilla').hide();
});
$('.wotlkHeader').click(function() {
$('#raid-progress-mop').hide();
$('#raid-progress-cata').hide();
$('#raid-progress-wotlk').show();
$('#raid-progress-tbc').hide();
$('#raid-progress-vanilla').hide();
});
$('.tbcHeader').click(function() {
$('#raid-progress-mop').hide();
$('#raid-progress-cata').hide();
$('#raid-progress-wotlk').hide();
$('#raid-progress-tbc').show();
$('#raid-progress-vanilla').hide();
});
$('.vanillaHeader').click(function() {
$('#raid-progress-mop').hide();
$('#raid-progress-cata').hide();
$('#raid-progress-wotlk').hide();
$('#raid-progress-tbc').hide();
$('#raid-progress-vanilla').show();
});
</script>
<span class="h4">Raid Progress <span class="mopHeader">MoP</span> <span class="cataHeader">Cata</span> <span class="wotlkHeader">WotLK</span> <span class="tbcHeader">TBC</span> <span class="vanillaHeader">WoW</span></span>
<div id="raid-progress-mop">
<ul id="raid-mop">
<li>Content A</li>
</ul>
</div>
<div id="raid-progress-cata">
<ul id="raid-cata">
<li>Content B</li>
</ul>
</div>
<div id="raid-progress-wotlk">
<ul id="raid-wotlk">
<li>Content C</li>
</ul>
</div>
<div id="raid-progress-tbc">
<ul id="raid-tbc">
<li>Content D</li>
</ul>
</div>
<div id="raid-progress-vanilla">
<ul id="raid-vanilla">
<li>Content E</li>
</ul>
</div>
Wrap your code in:
$(function(){ ... });
...which is the short form of:
$(document).ready(function(){ ... });
Cheers
You need to put the script underneath your markup. Either that, or put it inside document.ready callback:
$(document).ready(function() {
// code here
});
The problem is that when the script appears above the markup, it will execute before the HTML is loaded, and so the browser won't yet know about raid-progress-mop, etc.
How about doing that a little more dynamically inside a ready() function :
<script type="text/javascript">
$(function() {
$('[class$="Header"]').on('click', function() {
var myClass = $(this).attr('class').replace('Header', '');
$('[id^="raid-progress"]').hide();
$('#raid-progress-' + myClass).show();
});
});
</script>
jsBin demo
Wrap your code into a ready finction and this code I wrote is all you need:
$(function(){
$('span[class$="Header"]').click(function(){
var classNameSpecific = $(this).attr('class').split('Header')[0];
$('div[id^="raid-progress-"]').hide();
$('#raid-progress-'+classNameSpecific).show();
});
});
Explanation:
$('span[class$="Header"]') = target any span element which class ends with Header
Now just attach a click handler to all that spans.
Than, to hide all your div elements do:
$('div[id^="raid-progress-"]').hide(); = will hide any div which id starts with raid-progress-
and than you just need to target the div that contains the magic word:
$('#raid-progress-'+classNameSpecific).show();
$('.mopHeader') isn't defined yet. wrap your script with $(function(){...})
I have a bunch of menu items in a list format like so
<ul class="menu unselectable">
<li class="group">
Group Title
<ul>
<li class="groupItem i0">item 0</li>
<li class="groupItem i1 over">item 1</li>
</ul>
</li>
<li class="group">
Another Group Title
<ul>
<li class="groupItem i2">item 2</li>
<li class="groupItem i1">item 1 (if I hover here, the others should too</li>
</ul>
</li>
</ul>
The idea is, if I hover on one item with class i1 then all i1 items should behave the same. So I thought of adding a class over to all i1 items when I hover on any of them like so.
$(".groupItem").hover(
function () {
$(this).addClass("over");
},
function () {
$(this).removeClass("over");
}
);
The problem is I can't think of a way to identify what item has just been hovered on aside from $(this). To remedy this I thought of adding i1 as an id to items, but different dom nodes shouldn't have the same id. My next idea was to add the attribute value to the li items but to no avail (when I did a quick test with $(this).val() kept returning 0 regardless of the value actually stored in the node.
Is there any way I can add an identifier so I can just say $(this).<someIdentifier> , and target all the dom nodes with that identifier?
you can add an attribute groupID="{id}" and then call $(this).attr('groupID')
Element.prototype.secondId = '';
and than
document.getElementById('id5').secondId = 13;
As this you just set on any element a new property which you can use as you wish but is just in javascript not in html.
I don't recommend adding false attributes to elements, and this will work even if data attributes are not well supported by the user's browser:
$(".groupItem").hover(
function () {
var className = this.className.split(' ')[1];
$('.' + className).addClass("over");
},
function () {
var className = this.className.split(' ')[1];
$('.' + className).removeClass("over");
}
);
NOTE: Requires that classes are always organized as you specified above. A safer way could be:
var className = $.trim(this.className.replace('groupItem',''));
$(this).filter('#selector')
Please, Try working below code as below once:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
<style>
.menu{ display:inline;}
.menu li{ display:inline; float: left;width: 100px;}
.menu li ul{display:none;}
</style>
<script type="text/javascript">
$(document).ready(function(){
$(".group").hover(
function () {
$(this).find("ul").show();
},
function () {
$(this).find("ul").hide();
}
);
});
</script>
</head>
<body>
<ul class="menu">
<li class="group">
Group Title
<ul>
<li>GT 1</li>
<li>GT 2</li>
</ul>
</li>
<li class="group">
Trochlear Nerve
<ul>
<li>TN 1</li>
<li>TN 2</li>
</ul>
</li>
</ul>
</body>
</html>
i have a simple horizontal menu with four choices.
When i mouseover a div (e.g. div A), its child appears and
when i mouseout that specific div, its child disappears.
I have placed a setTimeOut function for mouseover (it is about 300).
In some specific conditions i would like to disable setTimeout
1. when i mouseout div A and i mouseover div B, i would not like to have that delay,
and i would like just to show the childDiv of B
2. when i mouseout div B and i mouseover div C, i would not like to have that delay,
and i would like just to show the childDiv of C
But how can i achieve that??
It's just that i have a series of events:
(a simple algorithm)
If(mouseout(divA) && mouseover(divB))
{
disable setTimeOut;
show(ChildDivB); //with no delay
}
else If(mouseout(divB) && mouseover(divC))
{
disable setTimeOut;
show(ChildDivC); //with no delay
}
}
Generally, when i mouseover && mouseout in "foo" div, (foo is the div that contains all divs) the settimeout shall be disabled.
Can this be done in jquery??
My code is as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
.myDiv {
border:1px solid red;
height:30px;
width:100px;
float:left;
}
.myDivChild {
display:none;
width:300px;
height:300px;
}
</style>
</head>
<body>
<div class="foo" style="background-color:#3300FF;width:900px;height:30px;margin-top:100px;">
<div class="myDiv" style="background-color:red;margin-left:100px">A
<div class="myDivChild" style="background-color:red">
Child Div A
</div>
</div>
<div class="myDiv" style="background-color:yellow">B
<div class="myDivChild" style="background-color:yellow">
Child Div B
</div>
</div>
<div class="myDiv" style="background-color:green">C
<div class="myDivChild" style="background-color:green">
Child Div C
</div>
</div>
<div class="myDiv" style="background-color:#00CCCC">D
<div class="myDivChild" style="background-color:#00CCCC">
Child Div D
</div>
</div>
</div>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
var interval;
$('.foo > div').hover(function(){
var $showDiv = $(this).find('div');
interval = setTimeout(function(){
$showDiv.show();
},300);
},
function(){
clearTimeout(interval);
$(this).find('div').hide();
});
</script>
</body>
</html>
Assign a variable then clear it like this:
var myInterval=setTimeout(...);
To disable:
clearTimeout(myInterval);
Be careful that the variable assigned to the setTimeout has scope where you clear the timeout.
Also, each variable holds only one interval. If you overwrite it it will not clear the previous timeout. (unless it's an array or object with multiple keys/properties in which case you cannot clear the whole array/object, you need to loop through them and clear each one at a time.)
You cannot do something like
If(mouseout(divA) && mouseover(divB))
because these are events, not variables. What you need to do is record a state of the application and then react to this state. For example, in the event handler function of mouseOut, set a variable
lastMouseOut = this;
Then, in the event handler function of mouseOver, you can do your comparison:
if ((lastMouseOut==divA) && (this==divB)) {...}
Make sure lastMouseOut is a global variable, not a local one in the handler function.
This is what I worked out as an example:
CSS
#menu li {
cursor: pointer;
}
#menu ul {
display: none;
}
HTML
<ul id="menu">
<li id="one" class="mainMenu">Menu 1
<ul>
<li>Submenu 1</li>
<li>Submenu 2</li>
<li>Submenu 3</li>
</ul>
</li>
<li id="one"class="mainMenu">Menu 2
<ul>
<li>Submenu 1</li>
<li>Submenu 2</li>
<li>Submenu 3</li>
</ul>
</li>
<li id="three"class="mainMenu">Menu 3
<ul>
<li>Submenu 1</li>
<li>Submenu 2</li>
<li>Submenu 3</li>
</ul>
</li>
</ul>
Javascript
$(function(){
$('.mainMenu').hover(
function(){doMenu(this)},
function(){undoMenu(this)}
);
});
function doMenu(el){
switch (el.id) {
case 'one':
case 'two':
$('ul', el).show();
break;
default:
var menuTimeout = setTimeout(function(){$('ul', el).show()}, 300);
$.data($('#menu'), 'menuTimeout', menuTimeout);
}
}
function undoMenu() {
$('#menu ul').hide();
cancelTimeout($.data($('#menu'), 'menuTimeout'));
}
http://jsfiddle.net/XJhLD/
First off, are you sure that you want a dropdown menu at all? Since mouseless devices are very common today, like an iPad, you will at least want a fallback solution. That being said, I can say that I also struggled with this issue (see their main menu) about a year ago.
Do not reinvent the wheel like I did if you don't have to. Have you tried searching for a small JS plugin/library? You may want to use the jQuery hoverIntent plugin for the delay stuff.