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

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}});
  }
});

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

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}});
  }
});

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)
}
});

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