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>
Related
I am trying to toggle a class on and off whenever i click on a list item. I have tried several things like using classList.toggle and wrapping the list elements in a anchor tag and then trying to add a class to the list items through that but the more things i try the more confused i get.
Here below is the snippet of my code.
var li = document.querySelectorAll("li");
li.addEventListener('click', (e) => {
addDoneClass();//
});
function addDoneClass() {
li.className = "done"
}
.done {
text-decoration: line-through;
}
<ul>
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
You might look at my JavaScript code an wonder why i done it that way that is because i was very confused at this point and that was the last thing that i tried.
const elements = document.querySelectorAll("li");
elements.forEach((element) => {
// First option
element.addEventListener('click', function() {
this.classList.toggle('active');
});
// Second option
//element.addEventListener('click', function() { customHandle(this); });
// Third option
//element.addEventListener('click', (e) => customHandle(e.target.closest('li')));
});
// For the second and third options
//function customHandle(element) {
// element.classList.toggle('active');
//}
li.active {
text-decoration: line-through;
}
<ul>
<li>Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
In my opinion, it's better if you add one event listener to the ul element, than have multiple for the li elements.
You can use classList.add("class") and classList.remove("class") functions, more information. You will also need to check if the current item already has the class, for that use the classList.contains("class") function.
Here's an example (updated with ternary operator):
const ul = document.getElementById("list");
ul.addEventListener('click', (e) => {
const li = e.target;
li.classList.contains('done') ? removeDoneClass(li) : addDoneClass(li)
});
function addDoneClass(li) {
li.classList.add("done");
}
function removeDoneClass(li) {
li.classList.remove("done");
}
.done {
text-decoration: line-through;
}
<ul id="list">
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
Tip: use the classList.toggle("class"), it does the same thing, but it's the cleaner way.
You Have To Use "this" Keyword To Reffer The Currently Clicked Element. You Can Achieve This Using JQuery Like This.
li.active { text-decoration : line-through; }
$("li").click(function () {
this.classList.toggle('active');
});
The problem is with scope.
function addDoneClass() {
li.className = "done"
}
In your context, li is an array of list items. Without running, I would guess that clicking on any list item was striking through all of the list items. Instead you need to pass the specific list item that you want changed.
li.addEventListener('click', (e) => {
addDoneClass(this); //this is the list item being clicked.
});
function addDoneClass(obj) {
// Now you can change to toggle if you want.
obj.className = "done"
// ie obj.className.toggle("done");
}
querySelectorAll returns a nodelist and addEventLister can only be applied to one node at a time. So to fix your code you should loop over each li in the list. And since you are using the event (evt) with addEventListener, you can use event.currentTarget to get the element clicked.
var listItems = document.querySelectorAll("li");
var listItemCount = listItems.length;
for (var i = 0; i < listItemCount; i++) {
listItems[i].addEventListener('click', (evt) => {
addDoneClass(evt);//
});
}
function addDoneClass(evt) {
evt.currentTarget.className = "done";
}
.done {
text-decoration: line-through;
}
<ul>
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
I have a dropdown menu with top level and two sub levels. The thing is that the sub levels work just fine, I can click on them and it takes me to the page I selected. The problem is with the top level, when I hover over it it displays the submenus but when I click on it it doesn't take me to the page.
var menu_Sub = $(".menu-has-sub");
var menu_Sub_Li;
$(".mobile-device .menu-has-sub").find(".fa:first").removeClass("fa-angle-right").addClass("fa-angle-down");
menu_Sub.click(function() {
if ($(".header").hasClass("mobile-device")) {
menu_Sub_Li = $(this).parent("li:first");
if (menu_Sub_Li.hasClass("menu-opened")) {
menu_Sub_Li.find(".sub-dropdown:first").slideUp(function() {
menu_Sub_Li.removeClass("menu-opened");
menu_Sub_Li.find(".menu-has-sub").find(".fa:first").removeClass("fa-angle-up").addClass("fa-angle-down");
});
} else {
$(this).find(".fa:first").removeClass("fa-angle-down").addClass("fa-angle-up");
menu_Sub_Li.addClass("menu-opened");
menu_Sub_Li.find(".sub-dropdown:first").slideDown();
}
return false;
} else {
return false;
}
});
menu_Sub_Li = menu_Sub.parent("li");
menu_Sub_Li.hover(function() {
if (!($(".header").hasClass("mobile-device"))) {
$(this).find(".sub-dropdown:first").stop(true, true).fadeIn("fast");
}
}, function() {
if (!($(".header").hasClass("mobile-device"))) {
$(this).find(".sub-dropdown:first").stop(true, true).delay(100).fadeOut("fast");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nav-menu">
<ul class="nav-menu-inner">
<li>
Home
</li>
<li>
<a class="menu-has-sub" href="about-us">About us <i class="fa fa-angle-down"></i></a>
<!-- Dropdown -->
<ul class="sub-dropdown dropdown">
<li>
<a class="menu-has-sub" href="clients-case-studies">Clients and Case Studies</a>
</li>
</ul>
<!-- End Dropdown -->
Any help would be appreciated. Thank you.
The problem arises in your return false call at the end of your first if statement:
menu_Sub.click(function () {
if ($(".header").hasClass("mobile-device")) {
menu_Sub_Li = $(this).parent("li:first");
if (menu_Sub_Li.hasClass("menu-opened")) {
...
}
else {
return false; // this prevents the default click action from occuring
}
});
What you are saying here is basically, if I click on the .menu-has-sub link and it doesn't have a .mobile-device class, I want it to return false.
That essentially means event.preventDefault() - read this SO answer for a great explanation event.preventDefault() vs. return false
But that seems to be your problem, be careful when preventing the default action on links, if you want them to go somewhere.
Here is a fiddle with the line commented out.
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>
I am using 'slideToggle' to open a couple divs on a site and want to ensure all of the divs are closed before another is opened. Is there a way to run a if..then to ensure a toggled div isn't open before opening another?
Here is my script;
<script type="text/javascript">
$(function()
{
$("a#toggle").click(function() {
$("#contact").slideToggle(500);
return false;
});
$("a#toggle_about").click(function(){
$("#about").slideToggle(500);
return false;
});
});
</script>
Calling tag;
<li>Contact Me</li>
And called div;
<div id="contact">blah, blah...</div>
And CSS;
#contact{display: none; padding: 7px; font-size: 14px;}
Thanks,
------EDIT------
This seems to work ok, I can control the transition by setting speed to 500 or 0. It just seems like a lot of code for a simple if..then.
Thanks for the suggestions and possible solutions.
<script type="text/javascript">
$(function()
{
$("a#toggle").click(function(){
if ($("#about").is(':hidden')){
$("#contact").slideToggle(500);
return false;
}else{
$("#about").slideToggle(500);
$("#contact").slideToggle(500);
return false;
}
});
$("a#toggle_about").click(function(){
if ($("#contact").is(':hidden')){
$("#about").slideToggle(500);
return false;
}else{
$("#contact").slideToggle(500);
$("#about").slideToggle(500);
return false;
}
});
});
</script>
Fiddle Example
If you add appropriate classes to your html and change the href to target the div it needs to open, you can significantly simplify your code.
<ul>
<li>Contact Me</li>
<li>About Me</li>
</ul>
<div id="contact" class="toggleable">blah, blah...</div>
<div id="about" class="toggleable">blah, blah...</div>
Now you can handle both links with a single event.
$(".toggler").click(function (e) {
e.preventDefault();
var target = $(this).attr("href");
$(".toggleable").not(target).hide();
$(target).slideToggle();
});
the end result is when you click on "Contact Me", about will hide if it is open, and contact will show if it is hidden or hide if it is shown.
http://jsfiddle.net/nYLvw/
You could implement a helper function to collapse any visible elements with a certain class, and then call that every time you're about to toggle a div.
The markup:
<div id="contact" class="toggle-content">blah, blah...</div>
The code:
function hideToggleContent() {
$('.toggle-content:visible').slideUp( 500 );
}
$(function() {
$("#toggle").click( function() {
var isVisible = $("#contact").is(':visible');
hideToggleContent();
if( isVisible ) {
return false;
}
$("#contact").slideDown( 500 );
return false;
});
$("#toggle_about").click( function() {
var isVisible = $("#about").is(':visible');
hideToggleContent();
if( isVisible ) {
return false;
}
$("#about").slideDown( 500 );
return false;
});
});
You might also check out the jQuery UI accordion, it's default behavior accomplishes the same. http://jqueryui.com/accordion/
UPDATE: Added Fiddle Link For Example
There are several ways to solution this problem.
Whenever you are tweening for effect, and you want to only tween if not already tweening, you will want to track the state of your tween.
Typically, you might have a trigger/toggler, and a target. I like to use closures to accomplish the state tracking. I might use something like this:
$(function () {
// closures
var $togglers = $('[selector][, selector]');
var $target = $('[selector]');
$target.tweening = false;
var tweenStop = function () {
$target.tweening = false;
};
var togglerClick = function () {
if (!$target.tweening) {
$target.tweening = true;
$target.slideToggle(500, tweenStop);
}
};
// handle the event
$togglers.click(togglerClick);
});
>> SAMPLE FIDDLE <<
I'm trying to make a drop down menu - upon the first hit on div it should extend,upon second hit it should come back where it was.I'm very new to javascript so I'm not really sure where I went wrong it looks perfect to me,the code:
$(document).ready(function() {
$("#firstList").hide();
$("#firstExtend").click(function()
{
if(("#firstList").hide == true)
{
$("#firstList").show("blind",250);
}
else
{
$("#firstList").hide("fade",250);
}
});
});
HTML:
<div id="firstExtend" class="list">Praplesti</div>
<ul id="firstList">
<li class="list">Nium</li>
<li class="list">cia</li>
<li class="list">kazkas</li>
<li class="list">tur</li>
<li class="list">but cj</li>
<li class="list">tikiuosiveiks</li>
</ul>
</div>
the if (object.hide) clause is a bit off. You can use .is(":property") to check. So in your case, do:
if ( $("#firstList").is(":visible") )
try this:
$(document).ready(function () {
$("#firstList").hide();
$("#firstExtend").click(function () {
if (("#firstList").is(':hidden')) {
$("#firstList").show("blind", 250);
} else {
$("#firstList").hide("fade", 250);
}
});
});