import interact from 'interact.js'; Template.recipeEditPart.onRendered(function() { var vm = this.viewModel; ko.applyBindings(vm, this.find('.recipeEditPart')); interact('.ingredients-content').dropzone({ ondrop: function(event) { var ingredientId = $(event.relatedTarget).data('id'); vm.addIngredient(ingredientId); } }); });
The UI would then render the list of ingredients from the observableArray, and will look like this:
Great. Now we need to allow the user to reorder the list items by using the little 'grab' icon on the left. I am sure it can be done with interact.js, but it is nowhere near as simple as dragula.js. Interact.js offers low level constructs to build pretty much anything with mouse and touch interactions, but it is harder to configure. Dragula.js is perhaps less powerful but it is very simple to use:
import dragula from 'dragula'; Template.recipeEditPart.onRendered(function() { ko.applyBindings(this.viewModel, this.find('.recipeEditPart')); setupSortableList($('.ingredients-list')[0], this.viewModel.ingredients); }); function setupSortableList(htmlList, observableArray) { var drake = dragula([htmlList], { moves: function(el, container, handle) { return !!$(handle).parents('.list-item-handle').length; } }).on('drop', function (el) { var item = ko.dataFor(el); observableArray.remove(item); observableArray.splice($(el).index(), 0, item); drake.remove(); }); }
Let's go over what is happening here:
- When meteor finishes rendering the template on screen it invokes the 'onCreated' method.
- Dragula is called with the html element whose child elements are draggable. In this case the ingredients list.
- An options object is passed with a 'moves' function. This is used to restrict the 'grab' icon as the only element that can initiate a drag (as opposed to the while list item).
- Hook up to the on 'drop' event, at this point we use knockout's ko.dataFor() to retrieve the view model associated with the list item. The information is used to modify the observable array of ingredients.
- A call is made to dragula to remove() the element that is being dragged. Since the UI will re-render based on the observable changes to the collection the dragged element is no longer needed and can be discarded from the DOM.
You can see the screen capture below for a sample of how the experience looks like. You can also visit the live demo or view the soure code.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.