[Todo List] Mark task as `completed` without removing it from the 'incomplete' list


#1

Hey - so imagine the app is a todo list with two columns.

  1. incomplete column which shows incomplete tasks
  2. completed column which shows completed tasks

Thing is, when I mark a task as completed, I don’t want it to jump from one column to another. In other words, I want the just-completed task to remain in the incomplete column but be marked as completed. Still, when the client refreshes the browser, I want the task to be in the completed column.

I found a way to make this work using the private Tasks._collection collection on the client, which only updates client data without syncing with the server. Therefore, when the client refreshes, the change to the client collection is not persisted.

I wanted to know if there was a cleaner way to do this. Here is the code.

// template.js (client)

Template.todo.helpers({
  'uncompletedTasks': function() {
    // should return incomplete tasks and tasks that have been completed
    // during this browser session
    return Tasks.find({$or: [{completed: false}, {justCompleted: true}]});
  },
  'completedTasks': function() {
    return Tasks.find({completed: true, justCompleted: null});
  }
});

Template.todo.events({
  'click .done-button': function() {
    Tasks._collection.update(this._id, {$set: {justCompleted: true}}); // here is what makes it work!
    Meteor.call('completeTask', this._id);
  }
});

// methods.js (both)

Meteor.methods({
  'completeTask': function(taskId) {
    Tasks.(taskId, {$set: {completed: true}});
  }
});

#2

You could use a null collection to add all of the documents to that collection and use that collection.

Template.todo.onCreated(function () {
  this.ClientTasks = new Mongo.Collection(null);
  Tasks.find().observe({
    added: doc => this.ClientTasks.insert(doc)
  });
});

This is not synced with the server, do whatever you want with it. You also don’t necessarily have to update it, so you could simplify your queries


#3

Thanks, but I’m not exactly sure how this would help? I still need sync with server to mark tasks as completed :slight_smile: There must be an easier way with an array tracking just-completed ids though.

EDIT: here is the code with an array as a ReactiveVar. Works but a bit more code though.

// template.js (client)

Template.todo.onCreated(function() {
  this.justCompletedTasksIds = new ReactiveVar([]);
});

Template.todo.helpers({
  uncompletedTasks: function () {
    return Tasks.find({
      $or: [{completed: false}, {_id: {$in: Template.instance().justCompletedTasksIds.get()}}]
    });
  },
  completedTasks: function () {
    return Tasks.find({
      completed: false, _id:  {$nin: Template.instance().justCompletedTasksIds.get()}
    });
  }
});

Template.todo.events({
  'click .done-button': function() {
    var completedIds = Template.instance().justCompletedTasksIds.get();
    completedIds.push(this._id);
    Template.instance().justCompletedTasksIds.set(completedIds);
    Meteor.call('completeTask', this._id);
  }
});

// methods.js (both)

Meteor.methods({
  'completeTask': function(taskId) {
    Tasks.(taskId, {$set: {completed: true}});
  }
});

#4

you could use codition in todo.js … you try code …this example :smile:
Template.todo.onCreated(function() {
if (Meteor.user()) {
this.subscribe(‘users’, Meteor.user().username)
}
});


#5

You could still sync with the server, but have a local collection that remains unchanged (basically a copy of your remote on created).

Essentially, you could update them independently