I have a function that targets the li elements of a div id called mk-featured-kits. All of this works perfectly.
(function() {
var myNode = document.getElementById('mk-featured-kits');
myNode.addEventListener("mouseover", function(e) {
console.log(e);
if (e.target.tagName === 'LI') {
// all happens here
}
})();
I am using Chrome to see the console log and it allows me to use this path for the LI's: e.target.tagName.
Since IE 8 and bellow doesn't read addEventListener event, I am using this (code bellow) to check for the feature. The problem is by using this technique I can't access the LI using: e.target.tagName === 'LI' because the event only sees myNode as a tagName === DIV.
(function() {
var myNode = document.getElementById('mk-featured-kits');
if (myNode.addEventListener) { // all browsers except IE before version 9
myNode.addEventListener ("mouseover", function () {myEvent (myNode)}, false);
} else {
if (myNode.attachEvent) { // IE before version 9
myNode.attachEvent ("onmouseover", function () {myEvent (myNode)});
}
}
function myEvent(myNode) {
console.log(myNode);
if (myNode.target.tagName === 'LI') {
// all happens here
}
})();
How can I access the LI as I did on the first script but using the technique of the second script. Thank you in advance.
This is the html code:
<div class="mk-column">
`<div id="mk-featured-kits">
<ul>
<li id="kit01">Link 01</li>
<li id="kit02">Link 02</li>
<li id="kit03">Link 03</li>
<li id="kit04">Link 04</li>
<li id="kit05">Link 05</li>
<li id="kit06">Link 06</li>
<li id="kit07">Link 07</li>
<li id="kit08">Link 08 </li>
</ul>
</div>`
`
Related
Apologies in advance I feel as if this is a very simple solution and I am in the middle of a severe brain fart. I am simply trying to grab the data-id of an item I am clicking using ES6 syntax but no matter which way I run it I keep getting undefined.
HTML
<ul>
<li class="list-item" data-id="item-1">Click me</li>
<li class="list-item" data-id="item-2">Click me</li>
<li class="list-item" data-id="item-3">Click me</li>
</ul>
JS
let $el = $('ul');
class List {
constructor($el) {
this.$el = $el;
this.$listItem = $el.find('li');
this.attachHandlers();
}
attachHandlers() {
this.$listItem.on('click', () => {
var data = $(this).attr('data-id');
console.log(data);
});
}
}
const _init = () => {
if ($el.length) {
$el.each((i, v) => {
new List($(v));
});
}
};
_init();
Ive simplified the code down as much as possible, anybody see what I am doing wrong here?
The problem is in your attachHandlers method. Since you are using an arrow function, this refers to the class and not the element that was clicked.
Change the arrow function to a regular function.
In addition to Josan's answer, if you want to continue using the arrow function, use it like this:
class List {
constructor($el) {
this.$el = $el;
this.attachHandlers();
}
attachHandlers() {
this.$el.on('click', 'li', (e) => {
var data = $(e.currentTarget).attr('data-id');
console.log(data);
});
}
}
For more discussion, refer to this thread.
Simpler and easier by just using JQuery:
$(".list-item").on('click', function() {
console.log($(this).data('id'));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="list-item" data-id="item-1">Click me</li>
<li class="list-item" data-id="item-2">Click me</li>
<li class="list-item" data-id="item-3">Click me</li>
</ul>
I am trying to find out which exact list item was selected in the navigation menu. With this information, I will remove the class active from the previous menu link and add it to the newly selected one.
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
JavaScript:
let menuClick = document.getElementsByClassName(".nav");
menuClick.addEventListener('click', changeActive(), false);
function changeActive(){
//enter code here
}
Using
Vanilla JS - DEMO
var menuItems = document.querySelectorAll(".nav a"); // Get all matching selectors; same as SizzleJS $(selector)
for(var i=0; i < menuItems.length; i++){ // Loop through each element and add click event listener
menuItems[i].addEventListener('click', function(event){ // adding event listener.
event.preventDefault();
for(var i=0; i < menuItems.length; i++){
menuItems[i].parentElement.className = ''; // remove current `active` class from parent element `li`. This is not the best approach for removing classes in Vanilla JavaScript; see this answer http://stackoverflow.com/a/2155786/2151050
}
this.parentElement.className = 'active'; // add `active` to current clicked element.
}, false);
}
I am not going to force you to use jQuery, but you should consider it for doing more, and writing less code. :). Here's the jQuery version
jQuery - DEMO
var menuItems = $(".nav a");
$(".nav a").on('click', function(event) {
event.preventDefault();
menuItems.parent().removeClass('active');
$(this).parent().addClass('active');
});
Get the first element of the nodelist for nav:
let menuClick = document.getElementsByClassName("nav")[0];
Attach an event listener (note: changeActive not changeActive()). This will use event delegation to catch the events that bubble up from the anchors.
menuClick.addEventListener('click', changeActive, false);
Now add some code to your function:
function changeActive(e){
// grab the element that's active
let active = this.querySelector('li.active');
// remove the class
active.classList.remove('active');
// add the active class to the parent of the clicked anchor
e.target.parentNode.classList.add('active');
}
DEMO
There is many way to do that:
You can use onhashchange to detect hash changes
function locationHashChanged() {
if(location.hash === "#pageOne") {
// do something
}
else if(location.hash === "#pageTwo") {
// do something
}
}
window.onhashchange = locationHashChanged;
Or simply can bind click event to menu items
HTML:
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
JS:
var navs = document.querySelectorAll('.nav a');
navs.click = function (e) {
document.querySelector('active').className.replace('active','');
var target = e.target;
taret.className += ' active';
};
here is way a way with javascript..Note you will have to loop to add a click handler to all objects in the menu.
here is a snippet
function click(e){
alert(e.target.innerHTML);
}
var el=document.getElementsByClassName('nav navbar-nav navbar-right')
for(var i=0;i<el.length;++i){
function t(i){
el[i].addEventListener('click',click,false)
}
t(i)
}
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
I am trying to create a basic megamenu for my site but I'm having problems with the menu opening and closing on one click. This is a basic version of the HTML:
<ul class="menu">
<li class="dropdown-toggle">
Toggle Dropdown
<ul class="dropdown-wrap">
<ul class="column">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
<ul class="column">
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
</ul>
</ul>
</li>
</ul>
And this is a basic version of the JavaScript:
$menu = $('ul.menu');
$menu.find('li.dropdown-toggle').children('a').click(function(event) {
var $wrap = $(this).siblings('.dropdown-wrap');
if ($wrap.hasClass('open')) {
closeDropdown($wrap);
} else {
openDropdown($wrap);
}
event.preventDefault().stopPropagation();
});
$('html').click(function() {
console.log('HTML FIRED');
if ($('.dropdown-wrap.open').length > 0) {
closeDropdown($('.dropdown-wrap.open'));
}
});
function closeDropdown($wrap) {
$wrap.removeClass('open');
console.log('Close');
}
function openDropdown($wrap) {
$wrap.addClass('open');
console.log('Open');
}
The problem is I'm getting an event is undefined error when running stopPropagation.
Uncaught TypeError: Cannot read property 'stopPropagation' of undefined
This is a jsfiddle of the error in action: http://jsfiddle.net/styphon/0go9ukky/
My questions are why is event undefined in this case? And if event is undefined why doesn't event.preventDefault() throw the same error? How can I get this working?
None of the search results have explained this behaviour so far and I can't understand why event is undefined.
event is defined. But preventDefault does not return the event. So you have to do it in two lines:
event.preventDefault();
event.stopPropagation();
You cannot chain methods from event object, ex: stopPropagation with preventDefault.
Code From jQuery Source:
preventDefault: function () {
var e = this.originalEvent;
this.isDefaultPrevented = returnTrue;
if (e && e.preventDefault) {
e.preventDefault();
}
},
As you can see that preventDefault does not return anything explicitly, so by default undefined is returned.
And you'll get error
Uncaught TypeError: Cannot read property 'stopPropagation' of undefined
To solve the issue use
event.preventDefault();
event.stopPropagation();
You can also use return false; as alternative to the two methods.
This question already has answers here:
Javascript onclick
(4 answers)
Closed 7 years ago.
I'm new in javascript and I'm trying to hide or show a submenu with the onclick event.
Here's the code:
javascript:
<script type="text/javascript">
bool shown = false;
document.getElementById("test").onclick = SubMenuDisplay();
function SubMenuDisplay()
{
alert("Hello World!");
if(!show)
{
$('subm').show();
shown = true;
}
else
{
$('subm').hide();
shown = false;
}
}
</script>
and html:
<li id="test">Account
<ul id="subm">
<li>Login</li>
<li>Sign up</li>
</ul>
</li>
but my onclick event doesn't work at all.
Is someone can help?
Here is what I believe you are trying to pull off:
Account
<ul id="subm">
<li>Login
</li>
<li>Sign up
</li>
</ul>
var shown = false;
$("#subm").hide();
function SubMenuDisplay() {
alert("Hello World!");
if (!shown) {
$('#subm').show();
shown = true;
} else {
$('#subm').hide();
shown = false;
}
}
Fiddle: http://jsfiddle.net/ryanpcmcquen/wyrogc77/
JavaScript is dynamically typed, so you do not need to declare types, as you did with bool shown = false;. This can be replaced with var shown = false;. JavaScript will figure out that this is a boolean.
Beyond that your code just needed a little massaging. You were assigning the id="test" to the li element, when you should just assign it to the a, and style the a like an li, with something like:
#test {
list-style-type: bullet;
list-style-position: inside;
display: list-item;
}
Just remove the ():
document.getElementById("test").onclick = SubMenuDisplay;
You are assigning the event with the function not the return value of the function. And make sure you are doing it after declaring the function, else it might throw an undefined error.
function SubMenuDisplay()
{
alert("Hello World!");
if(!show)
{
$('subm').show();
shown = true;
}
else
{
$('subm').hide();
shown = false;
}
}
document.getElementById("test").onclick = SubMenuDisplay;
Since you decided to use jQuery, then use it (I mean, go to jquery.com and read the doc):
$('#test > a').click(function (e) {
e.preventDefault();
$(this).next().toggle();
});
.subm {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li id="test">
Account
<ul class="subm">
<li>Login</li>
<li>Sign up</li>
</ul>
</li>
Looking for a solution on how to detect if a li has a child ul or ol i discovered jquerys has() which is pretty awesome apart from I need to detect if only the actual clicked li has a child ol, not any of its siblings. Are there any ways of doing this? The documentation doesnt cover this.
HTML
<ol>
<li><a class="delete-li" href="">Page 1</a></li>
<li><a class="delete-li" href="">Page 2</a></li>
<li><a class="delete-li" href="">Page 3 has ol</a>
<ol>
<li><a class="delete-li" href="">Page 4</a></li>
<li><a class="delete-li" href="">Page 5</a></li>
<li><a class="delete-li" href="">Page 6</a></li>
</ol>
</li>
</ol>
JS
$('.delete-li').live('click', function(event){
event.preventDefault();
item_id = $(this).attr('rel');
clicked = $(this);
////////////////////
//check if has sub pages
if(clicked.has('ol')){
answer = confirm('This will delete all sub pages and content are you sure?');
console.log(answer);
if(answer===true){gogogo=true;
}else{gogogo=false;}
}else{ gogogo=true;}
//if yes run AJAX delete
if(gogogo===true){
alert('LI REMOVED');
}
////////////////
});
Checkout the jsfiddle for the code.
has returns a jQuery object which is always true, as your handler is bound to a elements you can use next method and length property:
if ( clicked.next('ol').length )
Note that live method is deprecated, you can use on method instead.
$(document).on('click', '.delete-li', function (event) {
event.preventDefault();
var gogogo = false, $clicked = $(this), item_id = this.rel;
////////////////////
//check if has sub pages
if ($clicked.next('ol').length) {
gogogo = confirm('This will delete all sub pages and content are you sure?');
// console.log(gogogo);
}
if (gogogo === true) {
alert('LI REMOVED');
}
});
http://jsfiddle.net/jMF42/
You are binding the click handler to the a element. You need to be in reference to the li.
listItem = $(this).parent('li');
//check if has sub pages
if (listItem.find('ol').length) {
...
}
jsfiddle
You are calling function on <a> tag, which doesnt have child. If you want to get deeper you need to refer from his parent <li>.
$('.delete-li').on('click', function (event) {
event.preventDefault();
$this = $(this);
if ($this.parent('li').children('ol').length) {
answer = confirm('This will delete all sub pages and content are you sure?');
alert(answer);
} else {
alert('dont');
}
});
http://jsfiddle.net/NGmz6/