I'm trying to combine jQuery UI's draggable, droppable, selectable AND sortable libraries, to create a web interface for drag-selecting elements and dropping them into another area. The user will be able to remove items from the droppable area should they need to, and also control/cmd + click to select specific items without dragging.
So far I've made a pretty decent effort, but I'm having issues when it comes to adding "removed" items back into the original list of selectable items. The drag-selecting works well with these items (that are re-created dynamically), but my main problem is when control/cmd + clicking items once they have been added back to the original list.
To recreate the issue, add items to the second droppable area and then remove them (by clicking on them). Once the items are back in the original list, control/cmd + clicking the items you deleted doesn't select them properly, so when you go to drag these items, only one is added (instead of the correct amount).
Here's a jsfiddle: http://jsfiddle.net/b8key7Lw/
And here's the code I'm having difficulty getting to work once the #selectable > div items are dynamically created (around line 45 in the jsfiddle):
$("body").on("click", "#selectable > div", function(e){
if (e.metaKey == false) {
$( "#selectable > div" ).removeClass("ui-selected");
$(this).addClass("ui-selecting");
}
else {
if ($(this).hasClass("ui-selected")) {
$(this).removeClass("ui-selected");
}
else {
$(this).addClass("ui-selecting");
}
}
$( "#selectable" ).data("ui-selectable")._mouseStop(null);
});
Related
I am using a connected sortable that saves wonderfully via asp.net back-end on a button click. Additional features include the ability to search each of the lists. This works well until you do the drop and drag of an item from one list to another. When I do the search of the one list using JavaScript to search items in the one list, it still thinks that it is a part of the first list. Has anyone seen this behavior? and do you know of a possible fix to make item permanently part of the said dragged upon list within the DOM. This behavior is in FF, IE, Chrome, etc.
Now I do have buttons on this list that move items from one list to the other based on them being selected then button clicked, it is then a part of the second list using JQuery append();. This makes the item a permanent part of the second list's DOM and is able to be searched upon within that list.
So here is my "Ah-Ha" moment. It was doing what it was supposed to do looking for the item and showing it and if it was not the item it wouldn't show it. however when the item moved to the other column using sortable it still had the same class as the first column. I needed to make that switch.
The answer is here as follows...
http://jsfiddle.net/6jmLvysj/
$(input)
.change(function () {
var filter = $(this).val();
if (filter) {
//here is my DAH moment it is looking for this class so when the user was typing in the first search input it was looking for item it would be searching for it is the second column--give myself a Gib slap--
$(list).find(".ui-state-default:not(:Contains(" + filter + "))").hide();
$(list).find("ui-state-default:Contains(" + filter + ")").show();
} else {
$(list).find(".ui-state-default").show();
}
return false;
})
.keyup(function () {
$(this).change();
});
then this
//so here is where I changed this code when the user brings the item over then it changes it to the proper respected class depending where the user drops it so it can be searched.
stop: function (event, ui) {
if (ui.item.hasClass("ui-state-default")) {
ui.item.attr('class', 'ui-state-highlight');
}
else {
ui.item.attr('class', 'ui-state-default');
}
I have a home page with table and a few 'favorite' folders. These folders are for holding 'favorite' rows of information. Users drag and drop specific rows of information from the home table to the folder table. Rather than dragging the entire row (because my rows are very wide, and it can be unclear which folder you are dropping this row into), I have an icon before each case number that will ideally hold the information for said row. In this case, it's an arrow. What I need to happen is when you drag this arrow and drop it in this folder, the information from the 'dragged row' will append to the according 'favorite' table. This icon should disappear on drop, along with the corresponding row from the home page. Double clicking the folder will 'open' this folder to view favorite rows, both old and newly dropped. Here is my fiddle
$( ".drag" ).draggable({ revert: "invalid" });
$( ".dropTarget" ).droppable({
drop: function( event, ui ) {
var dropped = parseInt($(this).attr('title')) + 1;
$( this )
.attr('title',dropped+' entries');
var delay = $(this);
delay.prop('disabled', true).addClass('ui-state-highlight')
setTimeout(function() {
delay.prop('disabled', false).removeClass('ui-state-highlight');
}, 2000)
}
});
$( ".dropTarget" ).dblclick(function() {
$( ".fav1table" ).fadeIn();
$( ".main" ).hide();
//$(this).removeClass('glyphicon-folder-close').addClass('glyphicon-folder-open');
});
First of all, I recommend you to change the cursor type while hovering the arrow. This will help the user. What you need is to determine what lines allready have been added to favorite. A solution can be to create two CSS classes. normal and favorite. For each line that have already been "favorized", add class favorite. So you will have some arrows like class="drag favorite". In the CSS just set "favorized" arrows as invisible or undisplayed.
On the drop event of the .droppable() method, add the class "favorite" to the dropped arrow. So it will be not visible anymore. You can re-use this class later in a selector, to select all favorite rows for instance...
I have an interactive basket whereby the user can drag and drop an item into the basket. However, the same item cannot be placed in the basket twice (but it remains visible, albeit faded), so once it is in the basket, the draggable property must be disabled.
I tried doing this:
$("#product_badges li:not(.on)").draggable({
// Options here
});
However, as this just initiates the draggable() property, the element is still draggable even if I do add the on class to it when it has been dropped.
I therefore cannot see a way of achieving this without having several instances for the draggable property like so:
$("#product_badges li:not(.on)").each(function(){
$(this).draggable({
// Options here
}
});
With the above method I can then call the individual product_badge and disable dragging like so:
This only gets called once the item has been placed into the basket (dropped)
$('.item',$('#product_badges')).draggable('disable');
Is there a better way of achieving this? Can you set an HTML element to only be draggable if it does not have a particular class?
Update
See example here: http://jsfiddle.net/mB6GK/2/
use the cancel property.
$("#product_badges li").draggable({ cancel: ".no" })
fiddle:
http://jsfiddle.net/sGguz/
You could use the start event,
$("#container").draggable({
start: function( event, ui )
{ return !$(ui.helper).hasClass('nodrop'); }});
http://jsfiddle.net/mB6GK/4/
I'm trying to create a table of inputs that automatically adds a new row when you enter text in one of the inputs on the bottom line. For the most part, it works fine. However, I'm having some trouble with jQuery UI checkbox buttons.
The checkbox buttons are supposed to change their icon when clicked. This works fine for the original buttons, but the cloned button that appears when you add a new row doesn't work properly.
You can see it in jsfiddle here. To replicate the issue, put some text in the third input down. You'll see that a fourth row appears. If you press the fourth checkbox, you'll see the third checkbox is the one whose icon changes. The wrong button also gets ui-state-focus but doesn't actually get focus, which really baffles me, though the correct button does get ui-state-active and seems, as far as I can tell, to evaluate as having been checked properly.
To be clear, the two checkboxes do not have the same ID, and their labels are for the right checkbox - the createNewRow() function takes care of that. If you comment out the line that turns the checkboxes into jQuery UI checkboxes, you'll see everything works fine. If you console.log the value of $(this).attr('id') in the buttonSwitchCheck function, you'll see that it has the right ID there too - if you click the fourth button, it'll tell you that the id of $(this) is "test4", but it's "test3" (the third button) that gets the icon change.
I'm going mad staring at this and I'd appreciate any help people can give. Here's the code:
// Turns on and off an icon as the checkbox changes from checked to unchecked.
function buttonSwitchCheck() {
if ($(this).prop('checked') === true) {
$(this).button("option", "icons", {
primary: "ui-icon-circle-check"
});
} else {
$(this).button("option", "icons", {
primary: "ui-icon-circle-close"
});
}
}
// Add a new row at the bottom once the user starts filling out the bottom blank row.
function createNewRow() {
// Identify the row and clone it, including the bound events.
var row = $(this).closest("tr");
var table = row.closest("table");
var newRow = row.clone(true);
// Set all values (except for buttons) to blank for the new row.
newRow.find('.ssheet').not('.button').val('');
// Find elements that require an ID (mostly elements with labels like checkboxes) and increment the ID.
newRow.find('.ssheetRowId').each(function () {
var idArr = $(this).attr('id').match(/^(.*?)([0-9]*)$/);
var idNum = idArr[2] - 0 + 1;
var newId = idArr[1] + idNum;
$(this).attr('id', newId);
$(this).siblings('label.ssheetGetRowId').attr('for', newId);
});
// Add the row to the table.
newRow.appendTo(table);
// Remove the old row's ability to create a new row.
row.removeClass('ssheetNewRow');
row.find(".ssheet").unbind('change', createNewRow);
}
$(document).ready(function () {
// Activate jQuery UI checkboxes.
$(".checkButton").button().bind('change', buttonSwitchCheck).each(buttonSwitchCheck);
// When text is entered on the bottom row, add a new row.
$(".ssheetNewRow").find(".ssheet").not('.checkButton').bind('change', createNewRow);
});
EDIT: I was able to find a solution, which I'll share with the ages. Thanks to "Funky Dude" below, who inspired me to start thinking along the right track.
The trick is to destroy the jQuery UI button in the original row before the clone, then reinitializing it immediately afterwards for both the original row and the copy. You don't need to unbind and rebind the change event - it's just the jQuery UI buttons which have trouble. In the createNewRow function:
row.find('.checkButton').button('destroy');
var newRow = row.clone(true);
row.find('.checkButton').add(newRow.find('.checkButton')).button().each(buttonSwitchCheck);
Try using the newer method .on, that allows for delegation, which should help with the dynamic changes to your DOM:
$(".checkButton").button().each(buttonSwitchCheck);
$("table").on("change", ".checkButton", buttonSwitchCheck);
I'm not sure, but it might help with not having to worry about binding events to specific elements.
Also, you could use it for the textbox change event:
$("table").on("change", ".ssheetNewRow .ssheet:not(.checkButton)", createNewRow);
Here's your fiddle with my changes: http://jsfiddle.net/Cugb6/3/
It doesn't function any different, but to me, it's a little cleaner. I thought it would've fixed your problem, but obviously hasn't, due to problems with the button widget.
And funny enough, it doesn't seem they "support" cloning: http://bugs.jqueryui.com/ticket/7959
i think you are using deep clone, which also clones the event handler. in your create new row function, try unbinding the change event then rebind on the clone.
I have a requirement that very closely matches this Jquery demo, which is a simple shopping cart demo. Basically I need to make two enhancements into this demo.
I need a text input alongwith with the available "products". So when I drag-drop one of the products, the text fields should be dragged along with that, which will be filled by user in the "cart" field.
I need a "cross" in front of each item in cart, which can be used to delete a certain item. Jquery's "destroy" function doesn't seem to do that. So how can I accomplish deletion of items from shopping cart?
Thanks for all the help.
You can specify your own "helper" on the draggable definition. Whatever html you specify as your helper is what will be shown during the drag animation. In your sortable (the drop area in the demo) you can override the beforeStop function. In there you can replace the item with whatever you want to be actually dropped into your shopping cart. In that, you could add the X button with javascript or something to remove the item
I recently implemented this to drag from a datatable into a list, so had to convert the tr into an li. It works in jQuery 1.4 but I get strange results on the drop when I drag out of the top in 1.5, and I haven't resolved that yet. Here's my helper defintion
helper: function() {
var text = this.children[0].innerText;
var result = "<li id='"+this.id+"'>"+text+"</li>";
return result;
},
and here's my beforeStop function
beforeStop: function( event, ui ) {
var id = ui.helper.attr( "id" );
var text = ui.helper.text();
var li = "<li id='"+id+"'>"+text+"</li>";
$(ui.item).replaceWith( li );
}