I'm struggling to combine a list with a v-if directive in a Vue-Draggable component.
The use case is that users can order items in a long list, but also 'hide' sections of that list. The problem I encounter is that right after hiding items, VueJS draggable does not update the index. The strange thing is that after one-drag and drop event is completed (and has dropped the element in the wrong place due to the mismatch in index), the issue is resolved and subsequent drag and drop actions follow the view.
What I've tried:
Bind the elements with a :key variable
Use NextTick statements in all of the events that VueJS Draggable
fires (change, update, sort, move, start, end, etc)
Manually correct the oldIndex and newIndex value based on a second, fixed key parameter. I somehow seem to be unable to interfere with these indices being determined by the sortable plugin.
Manually emitting events to update the Draggable element after hiding/showing.
Does anyone have examples of succesfully combining show directives with draggable components?
OK, so the key here was in the difference between the V-if and V-show directives. I was using the former, which removes the items from the DOM and causes the update problems.
If you use the latter, the DOM items will basically stay intact and the issue doesn't exist in the first place. Closing and leaving here in case someone stumbles over the same issue.
Related
The Context
I am using BlueprintJS to create a custom data-table with type-ahead results which return in a Menu component (think Google Sheets with typeaheads). I would like to be able to use the keyboard arrow keys to navigate through this menu. I'm able to focus the menu when the ArrowDown key is pressed. Then using a keyboard handler on the Menu, I keep track of the index of the current selected item and highlight it with CSS, quasi-focusing each menu item.
Here is an example of what I'm working with. Simple Input with Menu
The Problem
First and foremost, this method doesn't actually focus the list item, which destroys any accessibility. Second, using this method I can't move between submenus since the key handler is only keeping track of the top level elements of the menu.
Potential idea
When the list data changes (as it is a dynamic typeahead), create an object of Refs and pass this to the MyMenu function, and create a clever keypress handler, calling ref.current.focus() on each keypress navigation. This would properly focus the list item for accessibility, but not sure if this is the correct way to do this.
Question
What would the proper way of handling this? Is there a different component structure I should be thinking about?
I am using select2 version 4.0.2(rc1)
What I am seeing is that when using select2 with isMultple=true, opening the dropdown and then dynamically removing the select from the DOM, the menu sticks around.
You can see it happening in the select2 examples by focusing on control so you see the time zone options, then in the console typing $('.s2-example').remove(). The list of options sticks around.
Edit: Above is an example of what I am trying to work around. What is happening in my case is the dom is being manipulated to remove the select box by a framework in such a way that I can't hook into it before it happens. What I am trying to do is find a way to respond to the element being removed in the hopes that I can manually remove the options list if it exists.
I'm trying to figure out a clean approach to handling this. I've tried hooking into destroy like so:
$("#select-2-id").on("destroy", function(){...})
but destroy doesn't appear to be fired.
I have considered using a mutation observer but that feels kind of hacky to me. Could anyone suggest a better way to handle this? Any advice would be appreciated. Thanks!
Definitely buried in the documentation (under adapters), but you should be calling the destroy method on the select by passing "destroy" to the jQuery object's .select2() method
$(".js-example-basic-multiple").select2('destroy');
This destroys the instance. You can then safely call .remove()
$(".js-example-basic-multiple").select2('destroy').remove();
I've built a sortable and connected with a draggable list just like plenty of others. However, if I don't use the clone helper on the draggable, the drag placeholder gets offset and the placement of it gets messed up. But when I do use clone, the cloned item doesn't have the item ID, which I was intending to pass back to the server on stop.
What's the best way to handle this? Should I use a data element on the li to store the 'value' of the li?
Second questions-- on stop I want to remove a class from the dropped element, and add a new class. However I can't figure out how to reference this element. this doesn't work, and the other objects passed in to the stop event are ui and event-- ui.helper looked like it may have the info I need, but this doesn't seem to work either.
Thanks!
Fiddle here:http://jsfiddle.net/37tdS/
I have a list of elements of different types. Each has a toggle which toggles their visibility. Now there are two ways to hide an element either detach it from DOM or set the visibility to hidden.
As I understand Angular still updates hidden elements so this may impact the performance. Is this true? With jQuery one can detach the element from DOM and then attach it again when it needs to be visible. But is this approach even a good practice in Angular?
From reading Angular documentation and its API it gave me an impression that Angular prefers that all templates/HTML are declared at the start and their content is dynamically changed with controllers. So if you want to add/remove elements you'd use an ng-repeat directive and then by removing elements from an array in the scope you can add/remove elements from the template. This works well with primitive elements of the same type. However, how does this work if you have a list of elements of different type?
Edited:
http://jsfiddle.net/k26bA
An example here would be a list of tools which can be made available with a checkbox. In the example the first approach has a static list of elements which can not be dynamically changed. Which means you need to know in advance which tools will be available.
The second approach has a list in the controller to which you add and remove tools and in the template use ng-repeat to iterate over that list and create the tools. However, I'm stuck here as a tool can be a button, a text field, checkbox or even a complex div.
I find it a little hard to have a model first here because this is just a part that hides and shows available controls as opposed to displaying a domain model.
A good example of what I'm thinking would be Google Maps where you can hide or minimise various controls on the map.
You probably need to familiarize yourself with the ng-switch directive. The inactive items in an ng-switch are entirely unhooked from the DOM, as opposed to an ng-hide or ng-show, which simply set the CSS styles to show or hide.
First here's a plunk: http://plnkr.co/edit/2gD0AB. This plunk doesn't seem to work correctly because $scope.$on("$viewContentLoaded") won't fire, but on my machine it works just fine and I hope you get the idea.
What I'm trying to do there is simply move field objects from $scope.fields to $scope.groupFields = [], $scope.listFields = [], $scope.dataFields = [] when dragging them to the appropriate droppable areas. I've manager to do this using jQuery UI and jQuery UI touch punch (just to be mobile safe).
If you drag an element from the fields box to the one of the empty boxes you'll notice nothing happens on the screen besides the field elements hanging around where you left them. But if do a console.log($scope.fields) in the drop event listener you'll notice that all of the field objects are correctly set inside each of the field boxes.
If you click the Add element button then you'll simply trigger console.log($scope.groupFields); and suddenly all the elements appear correctly in their corresponding boxes like intended in the first place.
After pulling my brains out and after searching the internet for some time I found out that $scope.$apply(), called in the drop event after the moveField function, actually fixes my issue.
And I don't understand why. Shouldn't there be a digest already running and updating the view based on what I'm doing in the controller?
Thanks!
Just because the code that handles these jQuery drop events is inside the controller, it doesn't mean it will run under the angularjs scope/word. For those changes to make effect, you will need to force the angularjs app to do a dirty checking on its models. That can be accomplished by calling $apply() or $digest() methods. You should always call one of these methods after handling an jQuery event that changes $scope properties or after a timeout (or interval).