First off let’s create a typescript interface, describing how our data will be structured. To-do components are pretty simple, we need to know a couple of things: the name of each item and whether it is checked or not. We will also handle the ToDoListItem
component props as a separate interface, using the initial interface as a base.
A good reason to start with typings before handling data is so you can have an overview of what is required and plan how you’re going to achieve your goal. We know that we need a name and checked status and we know we need to handle deletion and change (checked) at the item level – so we can cater for that and set up all the relations at the beginning.
Create a new folder and file at src/types/to-do-item.ts
– this is where we will write our types for the ToDoListItem
. The first interface we will create is ToDoItem
, this will describe the name
and checked
properties and corresponding types: string
and boolean
respectively.
interface ToDoItem {
name: string
checked: boolean
}
export type {
ToDoItem,
}
Don’t forget to export your types!
This interface will be used in the parent ToDoList
component to help structure our data and used in the ToDoListItem
component to define the props.
Both defineProps
and defineEmits
use a generic type which allows us to pass the types to the functions in question with this syntax: myFunction
. So we will pass ToDoItem
to our definition of props and for our emit definition, we will add another event for delete
.
Now with access to our delete event, we can create a function called handleDelete
to emit the event with our props.task
payload.
With access to our props, we can pass props.checked
as the default value to the ref
assigned to isChecked
.
We will use the @click
directive to assign the function we created a moment ago, handleDelete
. Clicking the DeleteIcon
then will trigger our delete
event – just as we wanted! We will also update .item__name
content with {{ props.task.name }}
– we use the handlebars syntax to bind and display data in the template.
Next up is rendering the list of items based off a bit of mock data for now. So we will have to create a component named ToDoList
and render our tasks.
handleChange(task, checked)"
:key="task.name + ix"
:task="task"
/>
We move our simple
and
elements from App.vue
and put it in our new ToDoList
component. In our script section we set up our props to receive tasks
, and utilise the ref
API and pass the tasks prop as our default value.
Don’t forget to give your ToDoListItem
a key relative to your v-for
loop – so we can just use task.name + ix
here.
We will require an event handling function for when the ToDoListItem
gets checked – we need to find the index of the current task and then set its checked value to be what is passed via the parameters for the event handler.
As we have tasks
setup with the ref API – we can easily update the data via the .value
property, selecting our index and then setting the checked
property with our boolean! Nice and simple.
Let’s not forget to change the App.vue
to check our new component is working!
Next up we should add an input to add new tasks and do some general styling updates. We add some basic markup and styling to our new markup.
handleChange(task, checked)"
@delete="() => handleDelete(task)"
:key="task.name + ix"
:task="task"
/>
The last part we need to do now is hook up an event handler when the user presses the Enter key. Luckily in Vue we can use a “key modifier” – which allows us to check for specific keys. We will add this event and key modifier, then use handleEnterKey
as the name for our event handler.
handleChange(task, checked)"
@delete="() => handleDelete(task)"
:key="task.name + ix"
:task="task"
/>
Our event handler handleEnterKey
will add a new ToDoItem
object at the beginning of the tasks array (using unshift
) and we will reset the inputs value so we can easily add another task afterwards.
const handleEnterKey = (event: KeyboardEvent): void => {
const input = (event.target as HTMLInputElement)
if (!input.value) return
tasks.value.unshift({
name: input.value,
checked: false,
})
input.value = ''
}
With all of this, we should now have a working to-do list that can add tasks, remove tasks and check/uncheck tasks!