I have a JQuery Sortable list with the ability to multi-select objects inside the list and sort them accordingly. This works fine, and is even interacting with a multi-select draggable list, but the one problem I can't seem to find the answer to is how the placeholder decides its position in the list. I currently set the Sortable helper much like you'd expect:
helper: function (e, element) {
var elements = $(element).parent().children('.highlighted').clone(); //all the items which are highlighted
$(element).data('multidrag', elements);
$(element).siblings('.highlighted').remove();
var helper = $("<div/>");
return helper.append(elements);
}
But when I have more than one item selected, and I want to move them down a position, the placeholder does not change. I would like to solve this without changing the size of the placeholder, since I feel that that wastes space. To illustrate what's happening:
Is it possible to register the size of this object as a single item of the list? Or somehow refresh the list so that the sort works as intended? Once a new placeholder is created, this issue disappears, so maybe it's possible to force a redraw on the placeholder? I've looked into each of these avenues, but none seem to be working for me. If more code is required to reproduce this, please let me know.
Related
I'm not sure whether I'm using the right terminology here - but here is an example:
https://gist.run/?id=57ed46429e4583eb4c3fb11814451a55
This is how it looks like in Chromium:
Basically, the entries on top (red outline) are a visualization of an array as the "first-level" data display; here one can toggle each element's selection, and make a multi-element selection (red background). The array that is the source of the "first-level" display is mydata in first-level-items.js.
Those items that are selected in "first-level", are then shown again in "second-level" (green outline); here the same information of name and value is displayed, although a bit differently. Here also one can toggle an elements selection - but only one "second-level" element can be selected. The array that is the source of the "second-level" display is myseldata in second-level-items.js.
The intent here, is that once a "second-level" selection has been made, a slider appears, to change the .value property of the particular object which is the selected array element.
My original question (which is why I started this post/example at all), was:
How do I ensure that whenever the slider is changed, the value is updated in both second-level and first-level display?
... however, for reasons beyond me, this in fact does work somewhat in this gist.run example (but it still doesn't work in my actual project, which forced me to come up with the example to begin with). Also it only works somewhat, in the sense that when loading the example page at first, after making first and second level selections, and then changing the slider, the .value will be updated in both first- and second-level display. But as soon as I try deselecting on second level - or changing the selection on second level - then updating stops. So, I guess this question still stands...
After a second-level selection has been made, deselecting on second level (by clicking to toggle) does NOT remove the slider; how can I have it behave like that?
The update happens only on the slider's onChange - basically, while you drag and slide, this component emits onSlide, but it will generate onChange only at the end when the mouse is released (that is, when the sliding has stopped). How can I update both first- and second- level display while the slider is sliding?
And finally - is this how this kind of a problem is best addressed in Aurelia? That is - I currently have one array in first-level-items.js; first-level-items.js then has a singleton reference to second-level-items.js, so it can call a method within it, to change a filtered copy of the array on the second level, which then serves as a source both for second-level display and the slider... Is there a better way to organise this?
Boy, this was a pain, but here's what I think is the solution:
https://gist.run/?id=c09fea3b82a9ebc41e0a4c90e8665b04
Here are some notes:
Apparently, there is something wrong applying if.bind or show.bind on the input element of the slider - instead, the input element should be put in an enclosing div, and the div should have if/show.bind applied
Furthermore, if.bind should not be used, as it re-instantiates the slider element - use show.bind so we can get a reference to the slider widget at start already, even if it is hidden
Seemingly, using TaskQueue in attached() is the only way to get a reference to the slider at start
Once we have a reference to the widget, re-apply it on each second level element, whenever they change
Do not set this.myselChanging to null to specify no target of the slider (simply count on hiding the slider appropriately)
For a continuous change (onSlide), simply use this.myselChanging.value = e.value; in the handler - both first-level and second-level values will be changed
Beyond this, it seems arrays are copied by reference, so the multi-level update happens without further intervention...
Though, would still love to know what is the proper way to do this...
I have a problem with my drag and drop code. I want to put multiple items (dragged) in three containers (drop), and then return all values put in the container (thanks to alert(droppableResults);). But this code only returns the first item dropped, and I went all of the items.
Thanks for your help!
I put code in jsfiddle.net for better understanding.
https://jsfiddle.net/vbyyvt2o/1/
The problem you have is that the data-r="" value gets overwritten with every drop.
This results in only the last drop being recorded (not the first one).
Since .dropAble can contain several elements that approach doesn't work. You might however remove the data-r attribute from .dropAble and add a data-q attribute to your.dragAble elements. Then you could modify your JS accordingly and it should work fine.
Here is a modified fiddle:
https://jsfiddle.net/vbyyvt2o/4/
I have form and list of objects at the same page. When I insert a new row, it is not very easy to see where the newly inserted row is placed. Therefore, I thought I could color/highlight the newly inserted row (and perhaps remove the highlight after a few seconds).
How can I do this? I think a way to do this could be using a method on the server which returns the inserted id (return Collection.insert(doc);) and on the client use a callback with
Meteor.call('insertDoc', function(err,result) {
// do something with result
});
I think I can use a reactive-var to save the id of the last inserted row and in the loop highlight the row with
{{#each docs}}
<li class="{{isActive}}">{{name}}</li>
{{/each}}
and have a helper to return active if this._id equals the reactive var with the last inserted id.
But is this the best way to do it? How can I remove the color after some seconds? I have seen such behaviour on many pages but I cannot find any tutorials/code snippets to achieve this.
I wrote a package that uses Meteor's UI hooks to fade items in and out of a list as they are added and removed, to help users maintain context as data changes:
https://github.com/mizzao/meteor-animated-each
There is a demo at http://animated-each.meteor.com/. You can see that as items are added and removed, they are faded in and out. If items are inserted off the screen, the visible area does not scroll.
This isn't doing exactly what you want, but you can use the same idea to highlight items as they appear as well, as opposed to the simple fade in.
Note that all of this happens at the UI rendering level - not the template/code level. The UI hooks are also not well documented right now, but they've been around for a while.
I don't know if your method is the best, but that's how I'd go about doing it.
As for the animation, I'd use a CSS3 animation. Plenty to choose from ( https://developer.mozilla.org/en-US/docs/Web/CSS/animation ), and you can easily make them fade to the standard color. The animation would also only be applied to the last inserted item (because of the way you did it, only the last item would have the "active" class)
The page I am developing requires that there be two lists, one of which to add items to and then order those items. I am using Jquery plugin called nestable where you can drag and drop list items. it works fine when there are items prepopulated in the list, but when i make an empty list i cannot drag items onto it. I have tried using the dd-empty class everywhere (divs in different locations the ol class, the li class) and nothing seems to work completely. The closest thing that works is setting the ol class to dd-empty. it creates an empty "slot" which i can drag one item to, however it does not allow me to drag anymore items or drag that item back to the original list.
Am i doing something wrong? maybe in my CSS? or is this just a bug that nestable has?
Let me know if you have any questions or need to see my code.
figured it out. set maxDepth to 0 to try to get rid of the nesting capability (why use nestable without nesting? stupid i know). switching it to 1 solved the problem.
Edit nestable.js and add style min-height to:
if (!this.dragRootEl.find(opt.itemNodeName).length) {
this.dragRootEl.append('<div class="' + opt.emptyClass + '" style="min-height:30px">');
}
Then you will drag to an empty list
OK, what I'm trying to do here is to have jQuery UI update the sortables that are displayed on the page when a new column is dynamically added to the page by cloning it. If you clone a column (demo page) the new column should be able to receive both items from the existing column lists as well as new items that can be dragged from list A at the top into one of the sortables. This works fine for the initial setup, but as soon as you clone and append a new column, things break; the newly cloned column is not recognized as a droppable target and I can also not drag new items from list A to the newly cloned column list.
Intuitively the sortable('refresh') command should be enough for the sortable to check if anything in the setup is changed and enable new elements to receive and handle sortable items. However, I try to do this when the button is clicked, but there seems to be no effect.
I also tried to bluntly call the whole sortable() plugin on the '.columnlist' selector again, hoping that it would initialize on new matched elements and would simply skip over the elements that have the sortable already.
Oh and of course I use clone(true, true) to make sure events and data come with it.
Please see the demo page here: http://labs.shifthappens.nl/dragsort/
Try the following:
Drag an item from list A to column list A or B. The drag to sortable works
Re-order items in column list A. Sortable works.
Click on the clone button. A clone of column C appears.
Try to drag any item (be it from list A or from another column list) to the cloned column C and behold: it does not respond. It is as if it doesn't exist.
Funny thing: if you already put items in the original column C and then clone it, the items that are in the cloned column CAN be moved to other lists, but once out, can't be moved back to the cloned list. As if it rejects its own offspring.
How can I make the cloned list(s) to be sortable and valid dropzones as well?
As pointed out by jaredhoyt it indeed was about deep cloning. Apparently jquery ui doesn't need deep cloned elements and in fact breaks if you do that and expect the new elements to be droppable targets too.
However I did find the need to do another $('selector').sortable() on the columns for the cloned list to be recognized. This is what jaredhoyt also did in his fiddle. This while for me intuitively the 'refresh' method would be the most elegant solution, no?
Anyway, case closed. I'm happy it was as simple as not cloning the column with data and events, just the HTML.