Learn Svelte: Adding, Editing and Estimating Tasks In The Pomodoro Technique App
Tags: svelte, javascript, webdev
Published: 2019-12-29 17:34:41

---
title: Learn Svelte: Adding, Editing and Estimating Tasks In The Pomodoro Technique App
published: true
description: Sharing my initial experience in learning Svelte getting started by creating a sample project, a pomodoro technique app. In this part we add a list of tasks to be completed using the pomodoro technique
tags: [svelte,javascript,webdev]
canonical_url: https://www.barbarianmeetscoding.com/blog/2019/12/29/discovering-svelte-adding-some-tasks-and-pomodoros
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/1ndayocmls8wg7iob21r.png
series: Learn Svelte
---

*This article was originally published on [Barbarian Meets Coding](https://www.barbarianmeetscoding.com/blog/2019/12/29/discovering-svelte-adding-some-tasks-and-pomodoros).*

[Svelte](https://svelte.dev/) is a modern web framework that takes a novel approach to building web applications by moving the bulk of its work from runtime to compile-time. Being a compiler-first framework allows Svelte to do some very interesting stuff that is unavailable to other frameworks like disappearing from your application at runtime, or allowing for a component centered development with HTML, JavaScript and CSS coexisting within the same Svelte file in a very web standards friendly fashion.

In this series we'll follow along as I use Svelte for the first time to build an app. I'll use my go-to project[^1] to learn new frameworks: A [Pomodoro Technique](https://francescocirillo.com/pages/pomodoro-technique) app, which is a little bit more involved than a TODO list in that it has at least a couple of components (a timer and a list of tasks) that need to interact with each other.

**In this part 3 of the series we continue our project by making it possible to create a list of tasks and estimate the number of pomodoros it will take to perform them. Let's get started!**

<!-- more -->

> Haven't read the other articles in this series? Then you may want to take a look at this <a href="https://www.barbarianmeetscoding.com/blog/2019/12/23/discovering-svelte">list of resources for getting started with Svelte</a> or <a href="https://www.barbarianmeetscoding.com/blog/2019/12/27/discovering-svelte-getting-started">the first part of building the Pomodoro Technique app</a>

## Starting a Daily Pomodoro Routine

When you follow the Pomodoro Technique, the first thing that you'll do everyday before you start working is to sit down and follow these steps:

1. Decide what tasks you want to achieve today, 
2. Estimate how many pomodoros it will take to fulfill them and, then
3. Prioritize them taking into account how many pomodoros you can realistically achieve

Let's improve our skeletal Pomodoro app to support this initial flow by providing a way to create and estimate Tasks.

## Defining a Way to Model a Task

The first thing that we need to do is to devise a way to model a task. In our current version of the app, a task is just a string that represents a description of whatever we need to get done:

```html
<script>
  const tasks = [
    "plan some fun trip with Teo",
    "buy some flowers to my wife",
    "write an article about Svelte"
  ];
</script>

<style>
  ul {
    list-style: none;
  }
</style>

<ul>
  {#each tasks as task}
    <li>{task}</li>
  {/each}
</ul>
```

But we need our tasks to be slightly more involved with information such as the number of pomodoros we expect the task will take, the status of the task (is it completed or not?) and the actual number of pomodoros the task took.

So we'll model the task using a class `Task` within a new file `Task.js` with some initial fields to cover our initial use case:

```javascript
export class Task {
  constructor(description="", expectedPomodoros=1) {
    this.description = description;
    this.expectedPomodoros = expectedPomodoros;
    this.actualPomodoros = 0;
  }
}
```

We can now replace the strings from our original example with instances of this class:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';

  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];
</script>
```

The UI remains the same for now. We've just changed the underlying way in which we represent a task. Now, let's make it possible to add new tasks.

## Creating new Tasks

Our goal for this tutorial will be to get to a working implementation of a Pomodoro technique app as soon as possible, so we'll focus on getting there fast with little regard for an amazing user experience or great design. We will center our development in getting the basic core functionality in place and later we will polish and refine.

In order to have a quick implementation of an editable list of tasks where one can add and remove tasks to their heart's content we're going to follow this approach. We'll:

1. Make all tasks editable by using inputs for each task
2. Add a button to add new tasks
3. Add a button to remove tasks beside each one of the tasks

### Making Tasks Editable

In order to make our tasks editable we are going to update our `TaskList.svelte` component. Instead of plain list elements:

```html
<ul>
  {#each tasks as task}
    <li>{task}</li>
  {/each}
</ul>
```

We'll use inputs:

```html
<ul>
  {#each tasks as task}
    <li>
      <input type="text" value={task.description}>
      <input type="number" value={task.expectedPomodoros}>
    </li>
  {/each}
</ul>
```

The example above seems like it's working but it really isn't. The `value={task.description}` only works one way, from the data into the template. But if a user tries to edit a task, the new description or pomodoros won't be reflected in the data. The way to establish a two-way data binding between data and template is by using the `bind:value` directive:

```html
<ul>
  {#each tasks as task}
    <li>
      <input type="text" bind:value={task.description}>
      <input type="number" bind:value={task.expectedPomodoros}>
    </li>
  {/each}
</ul>
```

And now we can edit task descriptions and the number of pomodoros we expect each task will take. Whenever we update the underlying data, it will be reflected in the inputs, and likewise, whenever we update the inputs, the changes we do will be reflected in the data.

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-editing-tasks.jpg" title="We can edit tasks! Yippi!" alt="A big Title 'IL POMODORO' followed by a list of editable tasks within input boxes">

Let's adjust the styles a little bit so that the input fields suit their content better:

```html
<style>
  ul {
    list-style: none;
  }
  .description {
    min-width: 400px;
  }
  .pomodoros { 
    max-width: 100px;
  }
</style>

<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description}>
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
    </li>
  {/each}
</ul>
```

Svelte styles are scoped to the component itself so I could've styled the `input` elements directly (with `nth-child` selectors for instance), but I like to use semantic named classes for two reasons:

* They are easier to read and make sense of
* If I happen to change the order of the inputs at some point in the future I won't break the styles of my app

Now it looks better! Nice!

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-edit-tasks-improved.jpg" title="Now the styles look better!" alt="A big Title 'IL POMODORO' followed by a list of editable tasks within input boxes">

### Adding New Tasks

The next thing we want to do is to be able to add new tasks. So we add a button that will perform that function:

```html
<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description} >
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
    </li>
  {/each}
  <button>Add a new task</button>
</ul>

```

Whenever we click on this button we will add a task to the list of tasks that we want to complete today. In order to do that, we handle the click event using the `on:{event}` directive so that every time a user clicks on that button a new task is created and added to our list:

```html
<button on:click={addTask}>Add a new task</button>
```

The `addTask` function belongs to the behavior-y portion of our Svelte component inside the `script` tag: 

```javascript
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';

  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];

  function addTask(){
    tasks.push(new Task());
  }
</script>
```

And now when I click on the button to add a new task... **nothing happens**. Hmm...

After some tinkering and troubleshooting I realized that the way Svelte knows whether something changes is through a new assignment. So we need to update our code above to the following:

```javascript
function addTask(){
  tasks = tasks.concat(new Task());
}
```

I also learnt some interesting things:

* Svelte has nice support for sourcemaps so I can look at Svelte code in Chrome Dev Tools. However, I cannot set a break point or use [logpoints](https://developers.google.com/web/updates/2019/01/devtools) inside the `addTask` method.
* With the aid of `console.log` inside `addTask` and the `{@debug tasks}` on the Svelte template I could see how the list kept growing but the template was never updated. After fixing the issue, as the list kept growing the `{@debug tasks}` was executed and logged the updated list of tasks.

```html
<script>
  import {Task} from './Task.js';

  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];

  function addTask(){
    tasks.push(new Task());
    console.log(tasks); // => this grows everytime
  }
</script>

<!-- this was only executed the first time -->
{@debug tasks}
<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description} >
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
    </li>
  {/each}
  <button on:click={addTask}>Add a new task</button>
</ul>
```

* It is very easy to inspect the generated code both within [the Svelte Playground](https://svelte.dev/repl/06fd5ef1f33943c2bd6eed8abe0f29c6?version=3.16.7) or when developing Svelte locally. The output JavaScript produced for pushing a task in the existing array is:

```javascript
function addTask() {
  tasks.push(new Task());
}
```

Whereas if we update the value of the `tasks` variable the following code is generated:

```javascript
function addTask() {
  $$invalidate(1, tasks = tasks.concat(new Task()));
}
```

That `$$invalidate` function must be the one that warns Svelte that data has changed and that the template (the part that depends on `tasks`) needs to be re-rendered.

Anyhow! Now we can add new tasks:

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-add-new-task.jpg" title="Now we can add tasks" alt="A big Title 'IL POMODORO' followed by a list of editable tasks within input boxes. There's a button to add new tasks.">

### Removing Existing Tasks

We can add tasks, so we should also be able to remove tasks whenever we change our priorities. In order to do that, we add a new button for each task:

```html
<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description}>
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
      <!-- NEW STUFF -->
      <button on:click={() => removeTask(task)}>X</button>
      <!-- END NEW STUFF -->
    </li>
  {/each}
  <button on:click={addTask}>Add a new task</button>
</ul>
```

And create a new `removeTask` method to perform the actual removing:

```javascript
function removeTask(task){
  const index = tasks.indexOf(task);
  tasks = [...tasks.slice(0, index), ...tasks.slice(index+1)];
}
```

JavaScript should really have an `array.prototype.remove` method... FizzBuzz it, let's do it (**one should never, ever do this at home or work. Only on hobby projects with zero stakes**). 

I add a new `ArrayExtensions.js` file with this beautiful thing:

```javascript
/**
 * Returns a new array without the item passed as an argument
 */
Array.prototype.remove = function (item) {
    const index = this.indexOf(item);
    return [...this.slice(0, index), ...this.slice(index+1)];
}
```

And update our `TaskList.svelte` component:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';
  import './ArrayExtensions.js';

  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];

  function addTask(){
    tasks = tasks.concat(new Task());
  }
  function removeTask(task){
    // It looks way nicer, doesn't it?
    tasks = tasks.remove(task);
  }
</script>
```

And now tasks can be removed:

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-remove-task.jpg" title="Now we can remove tasks!" alt="A big Title 'IL POMODORO' followed by a list of editable tasks within input boxes. There's a button to add new tasks.">

## A Slightly Better User Experience Using Svelte Lifecycle Hooks

Wouldn't it be nice if the newly created task description would come into focus when a new task is created? That way the keyboard friendly user of our app could press Enter on the *Add new task* button, type away the task and estimation, press Enter again on the button, and so forth. **Maximum productivity**.

In order to be able to add this type of functionality we need to know when a new input is added to the DOM, and have that new input get the focus. After taking a quick look at the Svelte docs I found that you can hook into the lifecycle of a component to solve this sort of things. The *afterUpdate* lifecycle hook is the one that's executed after the DOM has been updated with new data, so that sounds like a good candidate:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';
  import './ArrayExtensions.js';

  // Rest of the code has been collapsed for simplicity's sake

  afterUpdate(() => {
    console.log('Hello! I was updated!'):
  });
</script>
```

If we take a look at our app right now we'll see how every time the component is rendered we get that message printed in the console. Now we need to get a reference to that input element that gets created. Svelte has a special directive that may help with that `bind:this`. 

You can use it like this:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';
  import './ArrayExtensions.js';
  let lastInput;

  // rest of the code collapsed for simplicity's sake
</script>

<style>
/** styles collapsed **/
</style>


<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description} 
       bind:this={lastInput}>  <!-- THIS IS NEW! -->
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
      <button on:click={() => removeTask(task)}>X</button>
    </li>
  {/each}
  <button on:click={addTask}>Add a new task</button>
</ul>
```

And now that we have a reference to that input we can use it to make it come into focus when we create a new task:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';
  import './ArrayExtensions.js';
  let taskAddedPendingFocus = false;
  let lastInput;

  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];

  function addTask(){
    tasks = tasks.concat(new Task());
    taskAddedPendingFocus = true;
  }
  function removeTask(task){
    tasks = tasks.remove(task);
  }
  function focusNewTask(){
    if (taskAddedPendingFocus && lastInput) {
      lastInput.focus();
      taskAddedPendingFocus = false;
    }
  }

  afterUpdate(focusNewTask);
</script>
```

This solution seems quite brittle for several reasons, like the fact that I have an nagging feeling that I can only get away with it because the newly created input is the last input in the DOM. But it will work for now. Sometimes the right solution is the working solution. We shall pay our accrued technical debt soon enough. 

For the time being, enjoy with a nice focus behavior:

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-focus.gif" title="Creating tasks with nice focus" alt="An animated gif that shows me adding new tasks to a to do list and keeping focus in the description field.">

## Setting a Goal of Pomodoros for the Day and Keeping it

The final thing that we want to add to support the pomodoro startup flow is to have a way for the user to understand how many pomodoros they're comitting themselves to complete. A quick way to do that is to just sum all the estimated pomodoros for all tasks and show them to the user. 

This is a perfect feature because it's simple and it lets us experiment with the reactivity system in Svelte.

In Svelte, you can create properties that are computed from other existing properties. In this case, we need a new property that is the sum all of current pomodoros for all tasks. Such a property could look like this:

```html
<script>
	import { afterUpdate } from 'svelte';
  import {Task} from './Task.js';
  import './ArrayExtensions.js';
  let taskAddedPendingFocus = false;
  let lastInput;
  let tasks = [
    new Task("plan some fun trip with Teo"),
    new Task("buy some flowers to my wife"),
    new Task("write an article about Svelte"),
  ];
  $: allExpectedPomodoros = tasks.reduce((acc , t) => acc + t.expectedPomodoros, 0);

  /** rest of the code omitted for the sake of clarity. **/
</script>
```

The `$:` syntax tells Svelte that the `allExpectedPomodoros` property is a reactive value, and that it needs to be updated any time `tasks` is updated (The funny thing is that this is actual [valid syntax in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) which I've never used in my life).

Now we can add it to our markup:

```html
<ul>
  {#each tasks as task}
    <li>
      <input class="description" type="text" bind:value={task.description} bind:this={lastInput}>
      <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
      <button on:click={() => removeTask(task)}>X</button>
    </li>
  {/each}
  <button on:click={addTask}>Add a new task</button>
</ul>
<!-- New stuff here -->
<p>
  Today you'll complete {allExpectedPomodoros} pomodoros.
</p>
```

And we are done!

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-total-pomodoros.gif" title="Creating tasks with nice focus" alt="An animated gif that shows me adding new tasks to a to do list and keeping focus in the description field.">

## And What happens When There's no Tasks?

Ok, just one more thing. There's one last detail that'd be nice to have work out. What happens when there are no tasks? 

Right now we just show an empty void of nothingness but it'd be nice to show some encouraging message to our users to have them start the day with strength. Let's do that!

We can take advantage of Svelte's `{#if} and {:else}` blocks to show a message when there are no tasks yet. For example:

```html
{#if tasks.length === 0}
  <p>You haven't added any tasks yet. You can do it! Add new tasks and start kicking some butt!</p>
{:else}
  <ul>
    {#each tasks as task}
      <li>
        <input class="description" type="text" bind:value={task.description} bind:this={lastInput}>
        <input class="pomodoros" type="number" bind:value={task.expectedPomodoros}>
        <button on:click={() => removeTask(task)}>X</button>
      </li>
    {/each}
  </ul>
{/if}

<button on:click={addTask}>Add a new task</button>

{#if tasks.length != 0}
  <p>
    Today you'll complete {allExpectedPomodoros} pomodoros.
  </p>
{/if}
```

<img class="center shadow-small" src="https://www.barbarianmeetscoding.com/images/svelte-you-can-do-it.jpg" title="An inspiring message for when there are no tasks" alt="An inspiring message for when the user hasn't created any tasks yet">

> ### Looking for the source code for the pomodoro app?
>
> Look no more! You can find it on <a href="https://github.com/Vintharas/il-pomodoro-in-svelte">GitHub</a> ready to be cloned and enjoyed, or on <a href="https://svelte.dev/repl/06fd5ef1f33943c2bd6eed8abe0f29c6?version=3.16.7">the Svelte REPL</a> where you can tinker with it right away.


## Some More Reflections So Far

In general, working with Svelte has been quite pleasant. Here are some more thoughts to add to [the ones from the last article](https://www.barbarianmeetscoding.com/blog/2019/12/27/discovering-svelte-getting-started#some-reflections-so-far):

* **In general things still work mostly as I expect them to work and it is easy to troubleshoot and recover from errors**. I was surprised that `array.push` didn't trigger a component render but after diving into the issue I understand that it is much easier for the compiler to understand that changes happen on assignments. And it does make a lot of sense, it easier to think of having to update the values of things instead of learning a new API (like `setState` for instance).
* **It was a pity that I couldn't put breakpoints or logpoints in the `svelte` code in Chrome Dev Tools**. I really expected that to work but perhaps it requires some additional setup that I am unaware of. It does feel like **something that should be supported in a dev environment out of the box**.
* **It is really cool that the Svelte tutorials and the playground provide access to the code generated by the Svelte compiler**. It was fun to take a peek into the generated code and realize that the array.push wasn't generating an invalidating call. (This also shows that Svelte does have a runtime, albeit small, even though people often market it as completely disappearing once your app has been generated).
* The syntax for handling events, binding elements to data, the if and else blocks, it was non standard but quite reminiscent at times, and in general **easy to learn**. (Although that may be because of the experience I have with many other frameworks that implement similar capabilities with slightly different syntax)
* The `$:` reactive values are really easy to implement and render in your component.

And we have come to an end for today. Hope you enjoyed this article! Take care!