jquery nested li click event calls multiple times - jquery-ui

I have the following structure.
<ul id="browser" class="filetree">
<li><span class="folder">Folder 1</span>
<ul>
<li><span class="file">Item 1.1</span></li>
</ul>
</li>
<li><span class="folder">Folder 2</span>
<ul>
<li><span class="folder">Subfolder 2.1</span>
<ul id="folder21">
<li><span class="file">File 2.1.1</span></li>
<li><span class="file">File 2.1.2</span></li>
</ul>
</li>
<li><span class="file">File 2.2</span></li>
</ul>
</li>
<li class="closed"><span class="folder">Folder 3 (closed at start)</span>
<ul>
<li><span class="file">File 3.1</span></li>
</ul>
</li>
<li><span class="file">File 4</span></li>
</ul>
In js
I have the following function.
$("#browser li").click(function(){
});
When I clicked on li File 2.1.1.
The function calls 3 times
first time for li File 2.1.1 , second time for li Subfolder 2.1 and third time for li Folder 2.
Can anyone give me the solution to call the function exactly once?
Your Help is greatly Appriciated.
Thanks.

That is because you have many li elements under #broswer.
Try this instead:
$("#browser>li").click(function(){
//only direct children of #browser
//your code
});
Or you can use event.stopPropagation():
$("#browser li").click(function(event){
event.stopPropagation();
//your code
});

Change your function to
$("#browser li").click(function(event){
event.stopPropagation();
//do your other stuff
});
That way, the click on the lower-level li won't "bubble up" to the higher level li.

This is due to the fact events "bubble" up your dom so you if you click
File 2.1.1, it will also be heard by File 2.1 and File 2 to fix this change event to
$("#browser li").click(function(e){
//Your code here
e.stopPropagation();
});

Rather than use the click event on the li object add another element (in example span) and handle click in that. This way can still bubble for higher events just doesn't bubble through nested li.
//Run the following to see the no li bubble result
$(".nobubble").on('click',function(){
$("#result").append($(this).attr("data-id") +"<br />")
});
//uncomment the following to see the li bubble result
/*$(".bubble").on('click',function(){
$("#result").append($(this).attr("data-id") +"<br />")
});*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="bubble" data-id="li-a"><span class="nobubble" data-id="span-a">a</span>
<ul>
<li class="bubble" data-id="li-b"><span class="nobubble" data-id="span-b">b</span>
</li>
</ul>
</li>
</ul>
<div id="result">
</div>

Related

How can I make a jQuery UI Menu Button or find an already existing extension?

I've just started working with jQuery UI, and while at first it looked like a wonderful tool, I've found that it lacks exactly what I need: a menu button widget.
What I want is the functionality of the jQuery UI Menu Widget, but with some additional bits, primarily a button/clickable area that will show/hide the menu. This alone is simple enough, but what is driving me mad is adding the expected keyboard functionality to this. When a button expands a menu, one expects that clicking outside that menu or pressing ESCAPE will close that menu, and while this works for the widget's submenus, it isn't built into the main widget.
I've been reading about the Widget Factory and extending/modifying widgets, but I'm completely lost as to how to accomplish this specific problem, and I can't seem to find any answers to this that aren't many years old. I've even tried overriding the "collapse" function in the menu instance, but the problem is that I don't quite understand the flow of the code. I basically added an 'else' statement that calls the 'click' event on the button when the conditions for closing a submenu aren't met. This just creates all sorts of weird bugs and I know I don't really have any idea what I'm doing.
A code example of how this is done would be greatly appreciated, but this is a common enough website behavior that I imagine someone has already put this together. I'm just not finding anything up to date.
Thank you in advance!
If you do not find a Widget that is needed, you can combine various elements and use them together.
$(function() {
$(".widget button").button();
$(".widget button").click(function(event) {
event.preventDefault();
if ($("#menu").is(":visible")) {
$("#menu").hide();
} else {
$("#menu").show().menu("focus", null, $("#menu .ui-menu-item:first"));
}
});
$("#menu").menu({
select: function(e, ui) {
console.log(ui.item.text().trim());
}
}).hide();
});
.ui-menu {
width: 150px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="widget">
<h1>Widget Buttons</h1>
<button>A button element</button>
<ul id="menu">
<li class="ui-state-disabled">
<div>Toys (n/a)</div>
</li>
<li>
<div>Books</div>
</li>
<li>
<div>Clothing</div>
</li>
<li>
<div>Electronics</div>
<ul>
<li class="ui-state-disabled">
<div>Home Entertainment</div>
</li>
<li>
<div>Car Hifi</div>
</li>
<li>
<div>Utilities</div>
</li>
</ul>
</li>
<li>
<div>Movies</div>
</li>
<li>
<div>Music</div>
<ul>
<li>
<div>Rock</div>
<ul>
<li>
<div>Alternative</div>
</li>
<li>
<div>Classic</div>
</li>
</ul>
</li>
<li>
<div>Jazz</div>
<ul>
<li>
<div>Freejazz</div>
</li>
<li>
<div>Big Band</div>
</li>
<li>
<div>Modern</div>
</li>
</ul>
</li>
<li>
<div>Pop</div>
</li>
</ul>
</li>
<li class="ui-state-disabled">
<div>Specials (n/a)</div>
</li>
</ul>
</div>
Base Examples:
https://jqueryui.com/menu/
https://jqueryui.com/button/
You can also make use of the Widget Factory to create your own.

drag only main ul with jquery-ui?

i have a simple nested UL's and i need to make only main UL sortable not the sub UL
example
<ul class="blocks-list" id="sortme">
<li>
<img src="../templates/admin/images/icons/fugue/status.png" width="16" height="16"> Task name
<ul class="tags float-right">
<li class="tag-time">5 days</li>
<li class="tag-tags">Server</li>
<li class="tag-user">You</li>
</ul>
</li>
<ul class="mini-blocks-list">
<li>
<img src="../templates/admin/images/icons/fugue/status.png" width="16" height="16"> Task name
<ul class="tags float-right">
<li class="tag-time">5 days</li>
<li class="tag-user">You</li>
</ul>
</li>
</ul>
<li>
<img src="../templates/admin/images/icons/fugue/status.png" width="16" height="16"> Task name
<ul class="tags float-right">
<li class="tag-time">5 days</li>
<li class="tag-user">You</li>
</ul>
</li>
</ul>
when i used this Jquery Code
$("#sortme").sortable({
update : function () {
serial = $('#sortme').sortable('serialize');
$.ajax({
url: "sort_menu.php",
type: "post",
data: serial,
error: function(){
alert("theres an error with AJAX");
}
});
}
});
it made both UL blocks-list and mini-blocks-list sortable
what i need is only to make blocks-list LI's sortable not both UL's
It seems a limitation in jQuery sortable, you could try this plugin or this one if you don't find out a pure jQuery solution.
You can use the sortable items option to filter exactly what you need and to keep other items from being sortable. For example items: "> li". docs

How to properly apply values farmed from .each()

Markup:
<ul>
<li>
<ul id="ratx">
<li>Location</li>
<li class="bar"><span></span></li>
<li class="value">4</li>
</ul>
</li>
<li>
<ul id="ratx">
<li>Hotel Services</li>
<li class="bar"><span></span></li>
<li class="value">5</li>
</ul>
</li>
<li>
<ul id="ratx">
<li>Hotel Facilities</li>
<li class="bar"><span></span></li>
<li class="value">3</li>
</ul>
</li>
<li>
<ul id="ratx">
<li>Room Cleanliness</li>
<li class="bar"><span></span></li>
<li class="value">4</li>
</ul>
</li>
<li>
<ul id="ratx">
<li>Value for Money</li>
<li class="bar"><span></span></li>
<li class="value">1</li>
</ul>
</li>
</ul>
I want to represent User Ratings dynamically using JQuery so I made a function like this,
jQuery:
$("ul#ratx").each(function(index) {
var val = $(this).children(".value").text();
var barval = val * 40;
/* compute ratings */
$("li.bar span").css("width", barval);
});
Now, when I alert barval I get all 5 values but when I try to apply the "compute ratings" line, all it does is apply the last value that it finds. How should I go about this?
Sorry if the question is a confusing. I am not quite sure how to phrase everything.
The problem is that, while interating through each elements it find, it is applying a common value to all li.bar span. You should represent a single element, you are trying to apply to.
$(this).children("li.bar span").css("width", barval);
Update
Here is a working Demo
The snippet that worked was
$(this).find("li.bar").children("span").css("width", barVal );
Also, I changed the display property of the span to display: inline-block;
You are setting the css for all the elements in the set $("li.bar span"). So at the end, they all have the same width of the last parsed value.
Without seeing you markup, it's difficult to propose you a code solution though.

jQuery UI Sortable - ConnectToSortable issue

I'm trying to create a drag & drop interface for icons. Basically, I have three div containers, each one with an ordered list inside. The first list holds the icons (as <li><img /></li>), and the two remaining ones are empty and should receive icons being dragged, dropped, and sorted inside of them. Each empty list is associated to a row where the icons will be displayed in the front end.
I have also created a function to allow item selection on Ctrl/Cmd + Left Mouse Click, so that users can drop multiple icons at a time.
Everything works as expected, except for one single issue: the custom Ctrl/Cmd + Click option stops working on draggable elements that have already been dropped.
After realizing, I did some testing and narrowed it down as much as possible: it seems that the culprit is the ConnectToSortable parameter in the 'Draggable' function. If the parameter is commented out, the Ctrl+Click function works as expected. The problem is that I need to use this parameter in order to store all the icons associated to each empty list (row) so I can retrieve them later.
Here is my HTML code:
<div id="container">
<div id="row1" class="row">
<ol class="drop-container">
<li class='draggable'><span class="squares blue-squares"> </span></li>
<li class='draggable'><span class="squares blue-squares"> </span></li>
<li class='draggable'><span class="squares blue-squares"> </span></li>
</ol>
</div>
<div id="row2" class="row">
<ol class="drop-container">
<li class='draggable'><span class="squares red-squares"> </span></li>
<li class='draggable'><span class="squares red-squares"> </span></li>
<li class='draggable'><span class="squares red-squares"> </span></li>
</ol>
</div>
<div id="row3" class="row">
<ol class="drop-container">
<li class='draggable'><span class="squares green-squares"> </span></li>
<li class='draggable'><span class="squares green-squares"> </span></li>
<li class='draggable'><span class="squares green-squares"> </span></li>
</ol>
</div>
​
And Here is my JS code:
$(function() {
// Custom function for Ctrl-Cmd Left Mouse Click
$(".draggable, .ui-draggable").click(function(e) {
if (e.ctrlKey || e.metaKey === true) {
if (!$(this).hasClass("selected")) {
$(this).addClass("selected");
} else {
$(this).removeClass("selected");
}
}
});
// Draggable
$('.draggable').draggable({
connectToSortable: ".drop-container",
delay: 200,
drag: function(event, ui) {
$(".selected").removeClass("selected");
},
helper: "original",
revert: "invalid",
revertDuration: 300
});
// Droppable
$('.drop-container').droppable({
tolerance: "touch"
});
// Sortable
$('.drop-container').sortable({
appendTo: ".drop-container",
connectWith: ".drop-container",
items: ".draggable",
revert: true
});
// Disable selection of items
$("div, ol, ul, li, span").disableSelection();
});​
I made a JSfiddle to test this, and I was able to reproduce the error. I am using spans instead of actual images for the purposes of this test.
Am I doing something wrong or is this a jQuery UI bug? Any ideas or workarounds are most welcome and appreciated!
You should do
$('.drop-container').sortable("refresh");
once the items are dropped in. See: http://jqueryui.com/demos/sortable/#method-refresh

Jquery Sortable for child not working in IE

Guys i have the following UL elements. The nested UL(nestsort) items are sortable in the IE browser Version 7 , but the drag movement seems wired ,while it works smooth in firefox.Please click on this link http://jsfiddle.net/Ds7ds/1/ from IE , the code is in jsfiddle.
<ul id="sortable">
<li>
<p> item 1</p>
<ul id="nestsort">
<li>
Sub item 1
</li>
<li>
Sub item 2
</li>
<li>
Sub item 3
</li>
</ul>
</li>
<li>
<p> item 2</p>
</li>
</ul>
$("#sortable").sortable();
$("#nestsort").sortable();
This should work for you :
$( "#sortable" ).sortable({
cancel: "#nestsort"
});
$("#nestsort").sortable();
Wish you luck.

Resources