How do I write the jQuery in this code more efficient? - javascript

I have a basic todo list, with which I can click on the li element to toggle the .completed css class on and off. Besides when I click on the X, which is covered in a span inside the li, I can remove the li. Everything works fine, but my IDE told me I had a duplicated jQuery selector, which is $("ul"). How can I write this jQuery more efficiently?
// check off specific todo by clicking
$("ul").on("click", "li", function () {
$(this).toggleClass("completed");
});
// click on X to delete todo
$("ul").on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});
ul {
list-style: none;
}
.completed {
color: grey;
text-decoration: line-through;
}
#container {
width: 100px;
margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul>
<li><span>X</span> Code</li>
<li><span>X</span> Sleep</li>
<li><span>X</span> Eat</li>
<li><span>X</span> Run</li>
<li><span>X</span> Jump</li>
</ul>
</div>

The simplest thing to do is use chaining:
$("ul").on("click", "li", function () {
$(this).toggleClass("completed");
})
// click on X to delete todo
.on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});
The first call to .on() will return the jQuery object you constructed with the initial $("ul"). Thus, you can immediately make another call to .on().
In this particular case, the redundant $("ul") probably isn't that big of a problem, but it's good to get into the habit of minimizing your DOM lookups.
Alternatively, you can always just stash the jQuery object in a variable:
var $ul = $("ul");
// check off specific todo by clicking
$ul.on("click", "li", function () {
$(this).toggleClass("completed");
});
// click on X to delete todo
$ul.on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});

you can chain the methods together or store a reference to the selector object:
$("ul").on("click", "li", function () {
$(this).toggleClass("completed");
}).on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});
Or
var $ul = $("ul");
$ul.on("click", "li", function () {
$(this).toggleClass("completed");
});
$ul.on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});

Do chaining. jQuery is design to be used like that.
$("ul").on("click", "li", function () {
$(this).toggleClass("completed");
}).on("click", "span", function (event) {
// remove li
$(this).parent().fadeOut(500, function () {
$(this).remove();
});
// prevent event from affecting parents element
event.stopPropagation();
});

Related

Conditionally binding/unbinding event listeners

With the help of this post I was able to put together a menu that closes either by toggling a link or clicking outside of it (via mouseup). The problem is that because this mouseup event handler is bound to the document object this is constantly being fired regardless of whether the menu is open or not.
I was wondering how could I conditionally set this handler up only when the menu is visible? I don't necessarily want to invoke: $(document).off("mouseup"); outright in that this toggle is ever fired to initiate the event listener inside $toggleMenu.on("click", function() {...}) via $(document).on("mouseup")
$(function() {
var $toggleMenu = $(".toggle-menu"),
$menu = $(".menu");
$toggleMenu.on("click", function(e) {
e.preventDefault();
toggleUserMenu();
});
$toggleMenu.on("mouseup", function(e) {
e.stopPropagation();
});
$(document).on("mouseup", function (e) {
console.log("Event is still firing");
if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
$menu.hide();
}
});
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
$menu.hide();
} else {
$menu.show();
}
}
});
.toggle-menu {
color: #444;
display: inline-block;
margin-bottom: 15px;
text-decoration: none;
}
.menu {
border: 1px solid black;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Toggle Menu
<div class="menu">
Menu Item 1
Menu Item 2
Menu Item 3
</div>
I would move your $(document).on("mouseup") code to the toggleUserMenu like this:
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
$menu.hide();
$(document).off("mouseup.my-menu");
} else {
$menu.show();
$(document).on("mouseup.my-menu", function (e) {... });
}
Note, I am using events with namespaces there to avoid cases when $(document).off("mouseup"); will unsubscribe all mouseup handlers.
You could attach the event handler only when the menu is displayed and unattach the event handler when the menu is closed.
So, every time you show the menu, you attach the mouseup handler to allow closing the menu by clicking off menu.
When the menu is closed (by click off menu or by clicking the toggle link), hideMenu hides the menu and unsets the event handler so it won't be called upon further mouseup events.
Note that the mouseup handler is factored out of the .on() code so that .off() is able to reference and remove only that handler--that is to say, if you have other mouseup handlers present, they will remain intact.
http://jsfiddle.net/qmLucq9r/
$(function() {
var $toggleMenu = $(".toggle-menu"),
$menu = $(".menu");
$toggleMenu.on("click", function(e) {
e.preventDefault();
toggleUserMenu();
});
$toggleMenu.on("mouseup", function(e) {
e.stopPropagation();
});
var hideMenu = function() {
$menu.hide();
$(document).off("mouseup", mouseupHandler);
};
var mouseupHandler = function (e) {
console.log("Event is still firing");
if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
hideMenu();
}
};
function toggleUserMenu() {
var menuIsVisible = $menu.is(":visible");
if (menuIsVisible) {
hideMenu();
} else {
$menu.show();
$(document).on("mouseup", mouseupHandler);
}
}
});

Removing class if click outside of div (targetting class)

I have a menu where user clicks on link and list appears via .addClass( "show-nav" ).
Here is jsFiddle with JS code:
jQuery(".nav-js-trigger").each(function(){
this.onclick = function() {
var hasClass;
hasClass = jQuery(this).next().hasClass( "show-nav" );
jQuery('.show-nav').removeClass('show-nav');
if (hasClass === false) {
jQuery(this).next().addClass( "show-nav" );
}
}
});
I want to remove the class show-nav if the user clicks outside of the div with class show-nav. How do I do this?
I have seen examples of e.target div ID but not class, particularly not a scenario like this.
You can add an listener to the element with an event.stopPropagation() on it, and another listener to the body, to capture this event if not intercepted before.
Something like this:
$(".show-nav").on("click", function(event){
event.stopPropagation();
});
$("body").on("click", function(event){
$(".show-nav").hide(); // or something...
});
To simplify your use-case, here is a JSFiddle.
$(".trigger").on("click", function(event)
{
$(".menu").toggle();
event.stopPropagation();
});
$(".menu").on("click", function(event)
{
event.stopPropagation();
});
$(document).on("click", function(event)
{
$(".menu").hide();
});
.menu
{
display: none;
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
menu
<div class="menu">Hello</div>
$(document).on("click", function(e) { if ($(e.target).is(".trigger") === false) {
$(".menu").hide();
}
});

How to get the id of element when right clicked

I like to know how to get the id of li when i right click over this li using javascript or jquery.
<ul>
<li id="liid" class="collapsable">
<div class="hitarea collapsable-hitarea">
</div>
<span class="folder">Group1.2</span>
</li>
</ul>
I have the right click function.
$(document).bind("contextmenu", function (e) {
// code to get the id of current li
});
Can any one help me please.
Use .on('contextmenu', 'li')
$(function() {
$('ul').on('contextmenu', 'li', function(e) { //Get li under ul and invoke on contextmenu
e.preventDefault(); //Prevent defaults
alert(this.id); //alert the id
});
});
Demo
This uses event delegation on document and only fires if an li is clicked.
$(document)
.on('contextmenu', 'li', function(e) {
e.preventDefault();
console.log(this.id);
});
Compared to adding a handler on $('ul') or $('li'), this will only bind a single handler.
You can try this
$(function() {
$('li').on("contextmenu", function (e) {
alert(this.id);
e.preventDefault();
});
}
Demo
You can use this..
If you want open also Context Menu on right click then use below code:
$(function() {
$('ul li').on('contextmenu', function() {
alert(this.id);
});
});
and without Context Menu then use below code:
$(function() {
$('ul li').on('contextmenu', function(e) {
e.preventDefault();
alert(this.id);
});
});
Happy New year...

returning clicked li class in an ul javascript/jquery

My code (the html page):
<nav>
<ul>
<li id="homeLink">Home</li>
<li id="rekenLink">Rekenmachine</li>
<li id="bakkerLink">Parkeergarage</li>
<li id="garageLink">Bij de bakker</li>
<ul>
</nav>
The javascript/jquery behind it:
$(function () {
$("ul").click(function () {
// here I want to get the clicked id of the li (e.g. bakkerLink)
});
});
How do I do that?
Use the .on() method with signature $(common_parent).on(event_name, filter_selector, event_listener).
Demo: http://jsfiddle.net/gLhbA/
$(function() {
$("ul").on("click", "li", function() {
// here I want to get the clicked id of the li (e.g. bakkerLink)
var id = this.id;
alert(id);
});
});
Another method is to bind the event to li instead of ul:
$(function() {
$("li").click(function() {
// here I want to get the clicked id of the li (e.g. bakkerLink)
var id = this.id;
alert(id);
});
});
Use jQuery on() instead of click and pass li as selector.
$(function() {
$("ul").on('click', 'li', function() {
//Here this will point to the li element being clicked
alert(this.id);
});
});
on() reference - http://api.jquery.com/on/
$(function() {
$("li").click(function() {
alert(this.id);
});
});
edit: jsfiddle link
Handle the click event of the <li> instead of the <ul>.
You can then get this.id.
Use the event's target (The anchor that was clicked) and then grab its parent's id:
$(function() {
$("ul").click(function(e) {
alert(e.target.parentNode.id);
});
});
JSFiddle
here is one of the way to do. Make sure your using the latest jquery file.
$("ul li").on('click', function() {
console.log($(this).attr("id"));
});
You may try
$(function () {
$("li").click(function () {
var id = $(this).attr("id");
alert(id);
});
});
or
$(document).ready( function() {
$("li").click(function () {
var id = $(this).attr("id");
alert(id);
});
});

Close Element when clicking anywhere on page

I have an element on my page that is toggled on and off by clicking on a text link. I also need the element to hide when a user clicks ANYWHERE on the page outside of the element itself - this is my jQuery code - can someone please show me what modifications to make to do what I need?
$(function() {
$("#header-translate ul li").click(function() {
$("#header-translate li ul").toggle("slide", { direction: "up" }, 500);
});
});
Using jQuery's one function is perfect for this.
$(function() {
$("#header-translate ul li").click(function(e) {
e.preventDefault();
var $toClose = $("#header-translate li ul")
$toClose.slideToggle(500, function() {
if($toClose.is(':visible')) {
$('body').one('click', function(e) {
e.preventDefault();
$toClose.slideUp(500);
});
}
else {
$('body').unbind('click');
}
});
});
});
What this will do is assure that this click handler will only get executed once, and only when the element is shown.
I believe you need to add a click() handler to the $('body'), and also event.stopPropagation() to your element.
$(function() {
$("#header-translate ul li").click(function(e) { // don't forget that 'e'
$("#header-translate li ul").toggle("slide", { direction: "up" }, 500);
e.stopPropagation(); // so this doesn't register as a body click
});
$("body").click(function(e) {
$("#header-translate").hide();
});
});
You'll want to check if
$(function()
{
var elToHideSelector = "#header-translate li ul";
$("body").click(function(e)
{
if ( ! $(e.target).is(elToHideSelector + ',' + elToHideSelector + ' *') )
{
$(elToHideSelector).hide();
}
});
});
I've used this code:
$(function() {
$("#header-translate ul li").click(function(e) {
$("#header-translate li ul").toggle("slide", { direction: "up" }, 500);
e.stopPropagation(); // so this doesn't register as a body click
});
$("body").click(function(e) {
if ($('#header-translate li ul').is(':visible')) { $("#header-translate li ul").hide("slide", { direction: "up" }, 500);}
});
});
Add a click handler to BODY tag that will slide the element up and add event.stopPropagation() to the element that opens the element in the first place so the click to open is not send to BODY.
You can add a listener to the document (since the event bubbles up, you can capture it in a parent element)
$(function() {
$("#header-translate ul li").click(function() {
$("#header-translate li ul").toggle("slide", { direction: "up" }, 500);
$(document).one('click', function(){
$("#header-translate li ul").hide();
});
});
});

Categories