This is the sixth in a x part series about Meteor for beginners.
- Part One – Leaderboard: Add a button to change sort order
- Part Two – Leaderboard: Add a button to randomise players’ scores
- Part Three – Leaderboard: Add and remove scientists from the leaderboard
- Part Four – Todos: Make urls friendly
- Part Five – Todos: Add a button to remove all items
- Part Six – Todos: Add buttons to move items up and down
Let’s add the buttons to the UI first. I’ve decided to put them next to the delete button, so I will copy the html and css for the “destroy” class so that the UI is consistant.
<template name="todo_item"> <li class="todo {{done_class}}"> {{#if editing}} <div class="edit"> <input id="todo-input" type="text" value="{{text}}" /> </div> {{else}} <div class="move-up"></div> <div class="move-down"></div> <div class="destroy"></div> ...
#item-list .todo .destroy { cursor: pointer; position: absolute; margin-left: 50px; left: 5px; top: 15px; height: 20px; width: 20px; } #item-list .todo .move-up { cursor: pointer; position: absolute; left: 5px; top: 15px; height: 20px; width: 20px; } #item-list .todo .move-down { cursor: pointer; position: absolute; margin-left: 25px; left: 5px; top: 15px; height: 20px; width: 20px; } #item-list .todo .display, #item-list .todo .edit { margin-left: 80px; height: 100%; width: auto; float: left; padding-top: 18px; line-height: 1; } #item-list .todo:hover .move-up { background: url('/arrowup.png') no-repeat 0 0; } #item-list .todo .move-up:hover { background-position: 0 -20px; } #item-list .todo:hover .move-down { background: url('/arrowdown.png') no-repeat 0 0; } #item-list .todo .move-down:hover { background-position: 0 -20px; }
PS. I spent longer making the up down arrow icons in an image editor than writing the code for this post!
Items in each todo list are currently sorted by their timestamp:
Template.todos.todos = function () { ... return Todos.find(sel, {sort: {timestamp: 1}}); };
I will continue to use the timestamp to control the sort order. When the up button is clicked, set the current item’s timestamp to be 1ms less than the item above it.
Template.todo_item.events = { ... 'click .move-up': function() { var todos = Template.todos.todos().fetch(); var currentItemIndex = todoRanking(this, todos); if (currentItemIndex > 0) { var todoAboveMe = todos[currentItemIndex - 1]; Todos.update(this._id, {$set: {timestamp: todoAboveMe.timestamp - 1}}); } }
var todoRanking = function(todoItem, todoArray) { var ids = todoArray.map(function (todo) { return todo._id; }); return ids.indexOf(todoItem._id); };
We can do something similar to move an item down.
'click .move-down': function() { var todos = Template.todos.todos().fetch(); var currentItemIndex = todoRanking(this, todos); if (currentItemIndex < todos.length -1) { var todoBelowMe = todos[currentItemIndex + 1]; Todos.update(this._id, {$set: {timestamp: todoBelowMe.timestamp + 1}}); } }
See the code on github.