Selecting consecutive elements using jQuery selectable - javascript

I am trying the Serialize sample in jQuery.
I notice one behavior that I can select unrelated elements using mouse and Ctrl key.
I only want to select consecutive elements and not all elements on mouse clicks.
This is what is happening currently, its taking Item 1, 2 and 6 as the selections.
I want to only select consecutive elements and not unrelated elements by mouse click and add a validation error that you can only add consecutive elements like in the following screenshot.
This is the code, I am working on, currently:
$(function() {
$(`#selectable`).bind("mousedown", function(e) {
e.metaKey = true;
}).selectable({
selected: function(event, ui) {
//For toggling between select clicks
if ($(ui.selected).hasClass('click-selected'))
$(ui.selected).removeClass('ui-selected click-selected');
else {
$(ui.selected).addClass('click-selected');
console.log(ui.selected.innerText);
let selectedID = ui.selected.id;
$("#select-result").append(ui.selected.innerText);
}
},
unselected: function(event, ui) {
$(ui.unselected).removeClass('ui-selected click-selected');
}
});
});
#feedback {
font-size: 1.4em;
}
#selectable .ui-selecting {
background: #FECA40;
}
#selectable .ui-selected {
background: #F39814;
color: white;
}
#selectable {
list-style-type: none;
margin: 0;
padding: 0;
width: 60%;
}
#selectable li {
margin: 3px;
padding: 0.4em;
font-size: 1.4em;
height: 18px;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Selectable - Serialize</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.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>
</head>
<body>
<p id="feedback">
<span>You've selected:</span> <span id="select-result">none</span>.
</p>
<ol id="selectable">
<li class="ui-widget-content">Item 1</li>
<li class="ui-widget-content">Item 2</li>
<li class="ui-widget-content">Item 3</li>
<li class="ui-widget-content">Item 4</li>
<li class="ui-widget-content">Item 5</li>
<li class="ui-widget-content">Item 6</li>
</ol>
</body>
</html>
Here's the fiddle, which I am working on.

I think that there is 2 cases,
First case is when no item is selected on your list so you can select any element.
Second case : when one or many items are selected so you have to be sure that the item to select is neighbor of the selected items.
$(function () {
$(`#selectable`).bind("mousedown", function (e) {
e.metaKey = true;
}).selectable({
selected: function (event, ui) {
//For toggling between select clicks
if ($(ui.selected).hasClass('click-selected'))
$(ui.selected).removeClass('ui-selected click-selected');
else {
//case when no Item is selected on your list
let noItemIsSelected = !$(".ui-widget-content").hasClass('click-selected');
//Case when on of neighbor's Item selected
let oneOfNeighborsIsSelected = $(ui.selected).next().hasClass('click-selected') || $(ui.selected).prev().hasClass('click-selected');
if (noItemIsSelected || oneOfNeighborsIsSelected) {
$(ui.selected).addClass('click-selected');
console.log(ui.selected.innerText);
let selectedID = ui.selected.id;
console.log(event);
$("#select-result").append(ui.selected.innerText);
} else {
$(ui.selected).removeClass('ui-selected click-selected');
}
}
},
unselected: function (event, ui) {
$(ui.unselected).removeClass('ui-selected click-selected');
}
});
});
You can see the updated version of your code here

Related

Jquery file not loading on browser

When i open the html file on google chrome. It is just a blank page. Nothing is loading. If i take out the .js files it loads the content with the .css applied but never with the .js files. Whether I put the .js files in the or at the end of the it still does not show anything. I am using jquery btw and downloaded the file. all files are on the same folder. also tried both jquery-3.3.1.min.js and jquery-migrate-1.4.1.js if it makes a difference. Hoping someone can help. Thanks!
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="testing.css">
</head>
<body>
<div id="products">
<h1 class="ui-widget-header">Blocks</h1>
<div class="ui-widget-content">
<ul>
<li data-id="1" class="credit"> 10000$ </li>
<li data-id="2" class="debit"> -10000$ </li>
<li data-id="3" class="credit"> 10000$ </li>
<li data-id="4" class="credit"> -10000$ </li>
<li data-id="5" class="credit"> Bank </li>
<li data-id="6" class="debit"> Loan </li>
</ul>
</div>
</div>
<div id="shoppingCart1" class="shoppingCart">
<h1 class="ui-widget-header">Credit Side</h1>
<div class="ui-widget-content">
<ol>
<li class="placeholder">Add your items here</li>
</ol>
</div>
</div>
<div id="shoppingCart2" class="shoppingCart">
<h1 class="ui-widget-header">Debit side</h1>
<div class="ui-widget-content">
<ol>
<li class="placeholder">Add your items here</li>
</ol>
</div>
</div>
<script type="text/javascript" src="jquery-migrate-1.4.1.js"></script>
<script type="text/javascript" src="testing.js"></script>
</body>
</html>
.JS
$("#products li").draggable({
appendTo: "body",
helper: "clone"
});
$("#shoppingCart1 ol").droppable({
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
accept: ".credit",
drop: function(event, ui) {
var self = $(this);
self.find(".placeholder").remove();
var productid = ui.draggable.attr("data-id");
if (self.find("[data-id=" + productid + "]").length) return;
$("<li></li>", {
"text": ui.draggable.text(),
"data-id": productid
}).appendTo(this);
// To remove item from other shopping cart do this
var cartid = self.closest('.shoppingCart').attr('id');
$(".shoppingCart:not(#" + cartid + ") [data-id=" + productid + "]").remove();
}
}).sortable({
items: "li:not(.placeholder)",
sort: function() {
$(this).removeClass("ui-state-default");
}
});
// Second cart
$("#shoppingCart2 ol").droppable({
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
accept: ".debit",
drop: function(event, ui) {
var self = $(this);
self.find(".placeholder").remove();
var productid = ui.draggable.attr("data-id");
if (self.find("[data-id=" + productid + "]").length) return;
$("<li></li>", {
"text": ui.draggable.text(),
"data-id": productid
}).appendTo(this);
// To remove item from other shopping chart do this
var cartid = self.closest('.shoppingCart').attr('id');
$(".shoppingCart:not(#" + cartid + ") [data-id=" + productid + "]").remove();
}
}).sortable({
items: "li:not(.placeholder)",
sort: function() {
$(this).removeClass("ui-state-default");
}
});
.CSS
h1 { padding: .2em; margin: 0; }
#products { float:left; width:200px; height: 600px; margin-right: 20px; }
#products ul {list-style: disc; padding: 1em 0 1em 3em;}
.shoppingCart{ width: 200px; margin: 20px; float: left; }
.shoppingCart ol { margin: 0; padding: 1em 0 1em 3em; list-style-type: decimal; }
Use
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
Because jquery-migrate not contains entire jquery code.
Of course you can include script from local.
Issues:
Your HTML files do not have CDN links to jquery and jquery UI. They require in the same order. First, you need jquery CDN and second jquery UI cdn
You're using jquery in a testing.js file but you do not have document.ready function.
Solution:
1. Add cdn links for jquery and jquery UI
2. Wrap your javascript code within document.ready function.
Here is a MDN document
Solution

Close jQuery menu on mouseLeave

I am building a small drop-down container which appears when You hover on top of a menu item. When I hover on top of the menu item (e.g. Tools) the dropdown appears, I can move my mouse inside, but when the cursor leaves the dropdown menu, it does not go away. How am I able to achieve this?
I only managed to make it dissapear when you click somewhere outside of it.
Here is a Fiddle.
var dropdown = $('.nav-dropdown');
dropdown.hide();
$('#dropdownToggle').hover(function(e) {
e.preventDefault();
dropdown.show(200);
dropdown.addClass('active');
$(window).click(function() {
dropdown.slideUp();
});
e.stopPropagation();
});
SOLUTION by anima_incognita:
var dropdown = $('.nav-dropdown');
dropdown.hide();
$('#dropdownToggle').hover(function(e) {
e.preventDefault();
dropdown.show(200);
dropdown.addClass('active');
$(window).click(function() {
dropdown.slideUp();
});
$(".nav-dropdown").on('mouseleave',function(){
dropdown.slideUp();
});
e.stopPropagation();
});
here is edit in your code worked fine with me...added methods
var dropdown = $('.nav-dropdown');
dropdown.hide();
$('#dropdownToggle').mouseenter(function(e) {
e.preventDefault();
dropdown.show(200);
dropdown.addClass('active');
$(window).click(function() {
dropdown.slideUp();
});
$('#dropdownToggle').mouseleave(function(e) {
dropdown.slideUp();
});
e.stopPropagation();
});
Add this to end of your code:
$(".nav-dropdown").on('mouseleave',function(){
dropdown.hide();
});
Update your JS:
var dropdown = $('.nav-dropdown');
dropdown.hide();
$('#dropdownToggle').hover(function(e) {
e.preventDefault();
dropdown.show(200);
dropdown.addClass('active');
$(window).click(function() {
dropdown.slideUp();
});
e.stopPropagation();
});
$(".nav-dropdown").on('mouseleave', function() {
dropdown.slideUp('fast');
});
.nav-list {
.nav-list-item {
float: left;
list-style: none;
padding: 2rem;
background: tomato;
font-family: 'Helvetica', 'Arial', sans-serif;
a {
text-decoration: none;
text-transform: uppercase;
font-weight: bold;
color: #fff;
}
.nav-dropdown {
position: absolute;
background: turquoise;
padding: 2rem;
li {
margin-bottom: 2rem;
}
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav-list">
<li class="nav-list-item">
Services
</li>
<li class="nav-list-item dropdown-wrapper">
<a href="#" id="dropdownToggle" class="nav-link tools">Tools
</a>
<!-- dropdown -->
<ul class="nav-dropdown active" style="display: block;">
<li class="nav-dropdown-item">
Buyer Cost Sheet
</li>
<li class="nav-dropdown-item">
Seller Net Sheet
</li>
<li class="nav-dropdown-item">
Mortage Calculator
</li>
<li class="nav-dropdown-item">
Title Fees
</li>
<li class="nav-dropdown-item">
Refi Calculator
</li>
<li class="nav-dropdown-item">
Real Estate Forms
</li>
</ul>
</li>
<li class="nav-list-item">
Buyers & Sellers
</li>
</ul>
As you are using the hover function, the hover function specifies two function to trigger mouseenter and mouseleave event
You have defined only the mouseenter function and not defined the mouseleave function. So below is the updated JS code:
$('#dropdownToggle').hover(function(e) {
e.preventDefault();
dropdown.show(200);
dropdown.addClass('active');
e.stopPropagation();
}, function(e){
e.preventDefault();
dropdown.slideUp();;
dropdown.removeClass('active');
});

How to activate menu tab after refreshing

How can I activate a menu tab after refreshing?
Here are my code
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<style>
.menu{width: 600px; height: 25; font-size: 18px;}
.menu li{list-style: none; float: left; margin-right: 4px; padding: 5px;}
.menu li:hover, .menu li.active {
background-color: #f90;
}
</style>
</head>
<body>
<ul class="menu">
<li><a href='#'>One</a></li>
<li><a href='#'>Two</a></li>
<li><a href='#'>Three</a></li>
<li><a href='#'>Four</a></li>
</ul>
<script type="text/javascript">
var make_button_active = function()
{
//Get item siblings
var siblings =($(this).siblings());
//Remove active class on all buttons
siblings.each(function (index)
{
$(this).removeClass('active');
}
)
//Add the clicked button class
$(this).addClass('active');
}
//Attach events to menu
$(document).ready(
function()
{
$(".menu li").click(make_button_active);
}
)
</script>
Can anyone tell me How to resolve this issue ?
Just like #Johan said, store your last active tab in a localStorage or cookie. Since there is no noticeable difference in performance between the two. I suggest you use localStorage because it's much easier to use. Like this:
function make_button_active(tab) {
//Get item siblings
var siblings = tab.siblings();
//Remove active class on all buttons
siblings.each(function(){
$(this).removeClass('active');
})
//Add the clicked button class
tab.addClass('active');
}
//Attach events to menu
$(document).ready(function(){
if(localStorage){
var ind = localStorage['tab']
make_button_active($('.menu li').eq(ind));
}
$(".menu li").click(function () {
if(localStorage){
localStorage['tab'] = $(this).index();
}
make_button_active($(this));
});
});
Check out this fiddle.

JQuery - select-result show message on select

plugin demo: http://jqueryui.com/selectable/#serialize
Hello, I don't quite understand this "plugin" and specifically
result.append( " #" + ( index + 1) ); &
<span>You've selected:</span> <span id="select-result">none</span>.
I want the user to be able to select one of the following "buttons" and then a message to show in place of the Number selected (as in the demo)
So: You've selected: #2.
Would be: You've selected: UK, please goto this and do that etc...
im guessing the easiest way is with JavaScript
if "select-result" = 1 then
else
Sort of thing?
Any help Would be great! i hope this isn't a stupid question...
Code:
<html>
<head>
<title>jQuery UI Selectable - Serialize</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery- ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css" />
<style>
#feedback { font-size: 1.4em; }
#selectable .ui-selecting { background: #FECA40; }
#selectable .ui-selected { background: #F39814; color: white; }
#selectable { list-style-type: none; margin: 0; padding: 0; width: 60%; }
#selectable li { margin: 3px; padding: 0.4em; font-size: 1.4em; height: 18px; }
</style>
<script>
$(function() {
$( "#selectable" ).selectable({
stop: function() {
var result = $( "#select-result" ).empty();
$( ".ui-selected", this ).each(function() {
var index = $( "#selectable li" ).index( this );
result.append( " #" + ( index + 1) );
});
}
});
});
</script>
</head>
<body>
<p id="feedback">
<span>You've selected:</span> <span id="select-result">none</span>.
</p>
<ol id="selectable">
<li class="ui-widget-content">UK</li>
<li class="ui-widget-content">USA</li>
<li class="ui-widget-content">FR</li>
<li class="ui-widget-content">AU</li>
<li class="ui-widget-content">CA</li>
<li class="ui-widget-content">DE</li>
</ol>
</body>
</html>
the example in the plugins is showing the selected index.. you don't need to do that... what you need to do is get the text of selected and show it in span.. so use.. html() or text()..
try this
$(function() {
$( "#selectable" ).selectable({
stop: function() {
var result = $( "#select-result" );
result.html($(this).html()); // result.text($(this).text());
}
});
});
var index = $( "#selectable li" ).index( this );
This grabs the index of the element we've been passed. We don't need this line.
result.append( " #" + ( index + 1) );
The index is the position at which the element occurs while descending the DOM.
We can change the above lines to one simple thing.
$( ".ui-selected", this ).text().appendTo(result);
Edit: See above, this may refer to the entire ul, so we need to filter it by the item that is selected. If you are allowing for a multi-select, then see below.
$( ".ui-selected", this ).each(function(){
$(this).text().appendTo(result);
});

Multiple drop events in HTML5

I'm trying to create a drag and drop feature in HTML5 where I can drag from one list to another. I have one list with draggable items and another list with items that have drop events added. The problem is, regardless of what element I drop onto, the last drop event that was added is the one that gets called.
Thanks for any help or suggestions.
I've included my code below:
<!DOCTYPE html>
<head>
<title>List Conversion Test</title>
<style type="text/css">
#list, #cart {
display: inline;
float: left;
border: 1px solid #444;
margin: 25px;
padding: 10px;
}
#list p {
background-color: #036;
color: #fff;
}
#cart p {
background-color: #363;
color: #fff;
}
.listitem {
}
.listitem_done {
text-decoration: line-through;
}
.product {
background-color: #CCC;
}
.product_over {
background-color: #363;
}
</style>
<script type="text/javascript" src="http://html5demos.com/js/h5utils.js"></script>
</head>
<body>
<article>
<div id="list">
<p>On My List</p>
<ul>
<li class="listitem" id="L001">Shopping List Item #1</li>
<li class="listitem" id="L002">Shopping List Item #2</li>
</ul>
<div id="done">
<p>In My Cart</p>
<ul></ul>
</div>
</div>
<div id="cart">
<p>Cart</p>
<ul>
<li class="product" id="P001">Product #1</li>
<li class="product" id="P002">Product #2</li>
</ul>
</div>
</article>
<script>
// make list items draggable
var list = document.querySelectorAll('li.listitem'), thisItem = null;
for (var i = 0; i < list.length; i++) {
thisItem = list[i];
thisItem.setAttribute('draggable', 'true');
addEvent(thisItem, 'dragstart', function (e) {
e.dataTransfer.effectAllowed = 'copy';
e.dataTransfer.setData('Text', this.id);
});
}
// give products drop events
var products = document.querySelectorAll('li.product'), thisProduct = null;
for (var i = 0; i < products.length; i++) {
thisProduct = products[i];
addEvent(thisProduct, 'dragover', function (e) {
if (e.preventDefault) e.preventDefault();
this.className = 'product_over';
e.dataTransfer.dropEffect = 'copy';
return false;
});
addEvent(thisProduct, 'dragleave', function () {
this.className = 'product';
});
addEvent(thisProduct, 'drop', function (e) {
//alert(thisProduct.id);
if (e.stopPropagation) e.stopPropagation();
var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
thisItem.parentNode.removeChild(thisItem);
thisProduct.className = 'product';
handleDrop(thisItem, thisProduct);
return false;
});
}
// handle the drop
function handleDrop(i, p) {
alert(i.id + ' to ' + p.id);
var done = document.querySelector('#done > ul');
done.appendChild(i);
i.className = 'listitem_done';
}
</script>
</body>
</html>
This is why it's often a bad idea to define functions (such as callback functions) within a loop. You're assigning thisProduct within the loop, but it will be reassigned for the next iteration of the loop. The way your closures are set up, each callback is bound to the same variable thisProduct, and will use the latest value.
One possible fix is to create a new closure where thisProduct is needed such as
(function(thisProduct) {
addEvent(thisProduct, 'drop', function (e) {
//alert(thisProduct.id);
if (e.stopPropagation) e.stopPropagation();
var thisItem = document.getElementById(e.dataTransfer.getData('Text'));
thisItem.parentNode.removeChild(thisItem);
thisProduct.className = 'product';
handleDrop(thisItem, thisProduct);
return false;
});
}(thisProduct));
This jsFiddle seems to work for me now. See here for more explanation.

Categories