Skip to content

4: Update and Remove

Up until now, you have only inserted documents into our collection. Let's take a look at how you can update and remove them by interacting with the user interface.

4.1: Add Checkbox

First, you need to add a checkbox element to your Task component.

Be sure to add the readOnly attribute since we are not using onChange to update the state.

We also have to force our checked prop to a boolean since React understands that an undefined value as inexistent, therefore causing the component to switch from uncontrolled to a controlled one.

You are also invited to experiment and see how the app behaves for learning purposes.

You also want to receive a callback, a function that will be called when the checkbox is clicked.

js
import React from "react";

export const Task = ({ task, onCheckboxClick }) => {
  return (
    <li>
      <input
        type="checkbox"
        checked={!!task.isChecked}
        onClick={() => onCheckboxClick(task)}
        readOnly
      />
      <span>{task.text}</span>
    </li>
  );
};

4.2: Toggle Checkbox

Now you can update your task document by toggling its isChecked field.

First, create a new method called tasks.toggleChecked to update the isChecked property.

javascript
import { Meteor } from "meteor/meteor";
import { TasksCollection } from "./TasksCollection";

Meteor.methods({
  ..
  "tasks.toggleChecked"({ _id, isChecked }) {
    return TasksCollection.updateAsync(_id, {
      $set: { isChecked: !isChecked },
    });
  },
});

Now, create a function to change your document and pass it along to your Task component.

js
..

export const App = () => {
  const handleToggleChecked = ({ _id, isChecked }) =>
    Meteor.callAsync("tasks.toggleChecked", { _id, isChecked });
  ..
  <ul>
    { tasks.map(task => <Task key={ task._id } task={ task } onCheckboxClick={handleToggleChecked} />) }
  </ul>
  ..

Your app should look like this:

4.3: Remove tasks

You can remove tasks with just a few lines of code.

First, add a button after text in your Task component and receive a callback function.

js
import React from 'react';

export const Task = ({ task, onCheckboxClick, onDeleteClick }) => {
  return (
..
      <span>{task.text}</span>
      <button onClick={ () => onDeleteClick(task) }>&times;</button>
..

Now add the removal logic in the App, you need to have a function to delete the task and provide this function in your callback property in the Task component.

For that, let's create a new method called tasks.delete:

javascript
import { Meteor } from "meteor/meteor";
import { TasksCollection } from "./TasksCollection";

Meteor.methods({
  ..
  "tasks.delete"({ _id }) {
    return TasksCollection.removeAsync(_id);
  },
});

Then, let's call this method inside a handleDelete function:

js
export const App = () => {
  ..
  const handleDelete = ({ _id }) =>
    Meteor.callAsync("tasks.delete", { _id });
  ..
  <ul>
    { tasks.map(task => <Task
      key={ task._id }
      task={ task }
      onCheckboxClick={handleToggleChecked}
      onDeleteClick={handleDelete} 
    />) }
  </ul>
  ..
}

Your app should look like this:

In the next step, we are going to improve the look of your app using CSS with Flexbox.