Lesson 4
Completing and Listing Tasks in TodoList
Completing and Listing Tasks in TodoList

Welcome back to another exciting step in building your TodoList application! In this unit, we'll focus on enhancing your application's functionality by adding the ability to complete and list tasks. At this point, you've already mastered the basics of task management, such as adding and removing tasks. Now, let's enhance your application even further by implementing some new functions.

What You'll Build

In this lesson, you'll be extending your TodoList application with the following functionalities:

  • Complete Tasks: Implement the ability to mark a task as completed.
  • List Incomplete Tasks: Create a function to get a list of tasks that are still pending.
  • List Tasks by Priority: Add functionality to filter tasks according to their priority.
Function Examples

Here are a few Elixir functions that we'll use in implementing the new features:

  • Enum.map/2: Useful for transforming a list. For example:

    Elixir
    1Enum.map(tasks, fn task -> task.task end)
  • Enum.map/2: Another example with pin operator:

    Elixir
    1Enum.map(tasks, fn 2 %Task{id: ^id} = task -> %Task{id: task.id, task: task.task, status: :completed} 3end)

    Let's understand the above code snippet:

    • The ^ operator is used to match the value of the variable id in the pattern, so that the id in the pattern matches the value of the variable id.
      • The pin operator (^) is crucial here. It ensures that the pattern match only succeeds if the id field of the task is equal to the current value of id. This means ^id does not try to bind id to a new value—it uses the existing value of id and compares it with the id field of the %Task{} struct. Without the caret symbol, the pattern match would always succeed, and the id field of the task would be bound to the variable id.
      • If the current task's id matches ^id, the pattern match succeeds, and the anonymous function will proceed to the next step.
    • The = task part of the pattern match binds the entire task to the variable task.
    • The -> operator is used to separate the pattern from the body of the function.
    • The %Task{id: task.id, task: task.task, status: :completed} part of the function body creates a new task with the same id and task as the original task, but with the status set to :completed.
  • Enum.filter/2: Perfect for filtering tasks based on conditions. For example:

    Elixir
    1Enum.filter(tasks, fn task -> task.status == :pending end)
  • Enum.reject/2: Handy for removing elements that meet a certain condition. For example:

    Elixir
    1Enum.reject(tasks, fn task -> task.id == id end)

By the end of this unit, your TodoList application will provide users with enhanced task management capabilities.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.