Create Svelte Project0:00
Okay, let's start working on our to-do app so we have a practical example we can work with when learning Svelte. So I am going to make use of some boilerplate, just so the app looks decent in the browser, but I'll make sure to try to explain everything along the way. So right now I have nothing. Let's go ahead and install a project using Svelte. We'll copy this command. Go ahead and paste that in. Let's name it lcsvelte.todo. Let's go into that folder.
Let's name it lcsvelte.todo. Let's go into that folder. Let's go ahead and npm install. And I'll make a commit here for a fresh Svelte app. Actually, I have to init first. git add, git commit, fresh Svelte app. Let's open it up in VS Code, and let's get rid of some of the defaults here. So let's go into our app.svelte. Let's get rid of all the template for now, all of the styles as well. And let's not pass in a prop from the main.js.
Let's get rid of all the template for now, all of the styles as well. And let's not pass in a prop from main.js. So from here, we can remove the props here. Okay. Save that. And also for the HTML file it attaches to in public/index.html, there's also some global CSS here, which I don't want. So let me just comment that out. Now I'm going to add some CSS files. So let's create a new folder here for our CSS.
Add Global CSS1:17
Now I'm going to add some CSS files. So let's create a new folder here for our CSS. Create a new file. This one's going to be a reset.css. And I also want another one for our main styles. I'm just going to make it global here. But using component-based CSS is also an option. I'm just going to name this style.css. So I'm going to paste in some code to our reset, just a generic reset, which you can find from here.
So I'm going to paste in some code to our reset, just a generic reset, which you can find from here. Or you can use a normalize as well. Or if you make use of a framework like Tailwind, you don't have to do this. I'm also going to paste in some styles here. Again, mostly just so our app looks decent. Let's go ahead and save that. Let's go back to our apps felt. I'm going to paste in the template code here, which we'll go over. Again, not too long, only 63 lines of code.
I'm going to paste in the template code here, which we'll go over. Again, not too long, only 63 lines of code. And then we can import our two CSS files. So let's put that within the script section up here. Go ahead and save that. Let's run our server. npm run dev. And let's take a look at this in the browser. Okay, so that's how our app looks. We have basically four sections here.
So that's our starting point. Let's go ahead and make another commit. So let me stop this, git add, git commit, to-do, app, starting, point. So if you want to follow along from this commit, after you have the project on your computer, just do a git log, and then you can check out this commit here. So just grab this hash, do a git checkout that hash, and you should be at this point here. So let's go ahead and get started. Let's run our server again. Let's try to work split screen again.
Render To-Do List3:10
Let's run our server again. Let's try to work split screen again. Most of the work should be in this one component for now, and then later on, we'll break it up into multiple components. Let's start off with our to-dos, and let's see if we can list them out in this unordered list here. So right now it's just hard-coded, and there's only one hard-coded to-do here. So let's define a piece of state to hold our to-dos, and then we'll loop over them and display them here. So again, just define a variable.
display them here. So again, just define a $variable. So I'm just going to paste in an array of to-do objects. So we have three here, and we have these properties for each to-do. So an id, a title, isComplete, and isEditing, which we'll make use of later on when we edit the to-do. So again, this should be reactive, and now we should be able to loop over it within our list item here. So let's go ahead and make use of each so we can loop over this. So again, I'll make use of my snippet here, s-each, there it is, spelt each block, and
So let's go ahead and make use of each so we can loop over this. So again, I'll make use of my snippet here, s-each, there it is, spelt each block, and we have a list of to-dos. Let's refer to them as a to-do, or you can destructure the properties if you like. Let's go ahead and move this list item into there. So let's just move it up, okay? And we can replace our to-do.title here. I think that's what I named it. So let's just say to-do.title, okay. There we go.
Add New To-Dos4:23
So let's just say to-do.title, okay. There we go. Like I said in the last video, sometimes you do have to define a key here, and we might have to do that when we work with transitions and animations, but for now this should be fine. Now let's work on adding to-dos. So that should be in our form here. So whenever we submit this form, we want to add a new to-do. So we have a form up here. Let's go ahead and add an event listener for submitting the form.
So we have a form up here. Let's go ahead and add an event listener for submitting the form. So we can do on:submit, and then provide a method. So I'll name it addToDo. Let's go back to our script section and define that method. So I'll put it underneath our toDos here. Let's say addToDo. And for forms, usually you want to prevent the default action. So we can do, or we can pass in an event here and do event.preventDefault(). And that should work.
So we can do, or we can pass in an event here and do event.preventDefault. And that should work. But if you want, you can make use of event modifiers to do it in the template. So down here. So we can say @click.prevent, and that should be the same thing, but we no longer have to do it in here. So again, similar to Vue, where you can do that as well. So we have our array of toDos, and we just want to add a new item to it. So there are a few ways to do this. If you make use of the array methods like push, then you're going to have to do an extra
So there are a few ways to do this. If you make use of the array methods like push, then you're going to have to do an extra step to make sure the to-dos are updated. So let's take a look at that first. We have our to-dos. If we use push, we can push a new to-do here. So for now, I'll just hard code it. So we'll grab one of these. Let's paste that in. Let me just update the ID here and the content.
Let's paste that in. Let me just update the id here and the content. And let's see what we get here. Let me save this. Let's go ahead and just type anything in here. Again, it's just hard coded for now. And let's see if it updates the to-do list. And it doesn't. That's because in Svelte, in order to trigger a re-render, we have to reassign that variable. So because we're making use of the push method, we're not reassigning the toDos variable.
You can also make use of the array spread operator to add new items. So let me just copy this to-do item. Let's comment this out. And then we'll make use of array spread instead. So we can say toDos equals. And doing it this way does have a reassignment. So we don't have to do toDos equals toDos after this. So we can just use the spread operator. So ...toDos. And then we can pass in the new toDo.
So dot dot dot to-dos. And then we can pass in the new to-do. So let's paste that in. Save that. Let's give it a try here. And that does work. So I'll just stick to this way. But either way works fine. Now let's work on actually adding the to-do that the user types in here. So we want to make use of two-way data binding to grab whatever the user types in here.
Now let's work on actually adding the to-do that the user types in here. So we want to make use of two-way data binding to grab whatever the user types in here. So let's make a new piece of state for that. Let's put it right here. We can name it toDoTitle. Okay. Empty string by default. And within our input type equals text. So where is that? Right here.
So where is that? Right here. We can make use of the toDoTitle. Okay. And now it should be making use of two-way data binding. So this variable should update as we type into the text box. And now we can update our method to make use of that variable instead. So right here, let's say toDoTitle. Let's also clear it out after it's submitted. So let's say toDoTitle equals an empty string.
Let's also clear it out after it's submitted. So let's say toDoTitle equals an empty string. And we also want to update our toDoID, which we don't have a piece of state for. So let's add that as well. So I'm going to add a toDoID here. Let's put it up here. Just so we can keep track of our IDs as we add them. So toDoID, let's start it at 4, because we have 3 by default. And then we'll just increment it every time we add a new toDo. So after this, we can say toDoID plus plus.
And then we'll just increment it every time we add a new to-do. So after this, we can say to-doID plus plus. Okay. Save that. Sorry, this should go outside of this right here. Let's give that a try, adding a to-do. Okay, cool. So now it's adding whatever we type in, and it should be incrementing the to-doID as well. Now let's work on deleting to-dos.
Delete and Complete To-Dos8:56
well. Now let's work on deleting to-dos. So again, we can make a new event listener for the delete button, which should be right here. So we have a button, which is meant for deleting. Let's say onClick equals. Let's make a method named deleteToDo. And we have to pass in the toDoID. Let's go ahead and define that method up here. Let's put it after addToDo.
Let's go ahead and define that method up here. Let's put it after addToDo. So right here, deleteToDo, takes in an id, and we can just make use of the filter method to filter out the to-do we want to delete. So we'll say toDos equals. So we are reassigning it, so it should be reactive. And we'll make use of the filter method, toDos.filter. And we want to keep everything that is not equal to the to-do id being passed in. So toDo.id does not equal the id coming in. Okay, save that.
So to-do.ID does not equal the ID coming in. Okay, save that. And let's see if it works. So over here, let's try deleting this one. And it does work. Cool. Now let's work on checking to-dos. So every time we check this, we want a line through to show on the to-do. So I do have a class named LineThrough that will add the CSS for that. So let's take a look at that first.
So I do have a class named LineThrough that will add the CSS for that. So let's take a look at that first. So it should be right here for our to-do item. So if I add that class, LineThrough, it should add that line through, and it does. So we only want to show this when the to-do is complete. So by default, let's add one that is complete. So let me go up here to my to-dos. Let's say this one is complete. Actually, it already is. So let's go ahead and add that line through for any complete to-dos.
Actually, it already is. So let's go ahead and add that lineThrough class for any complete to-dos. So there are a few ways you can do this. We can just use a ternary here. So if we say, if to-do.isComplete, then go ahead and render the lineThrough class. But if not, then render nothing. And that should work, hopefully. Let's save that. And it does work. Or you can make use of Svelte's conditional class rendering, which will work as well.
And it does work. Or you can make use of Svelte's conditional class rendering, which will work as well. So ternary is good to use when you actually have two cases. For example, one case you want this class, but the other case you want another class. You can see for this case it's empty, so it's better to use conditional class rendering here. So let's get rid of this. Let's add another class here. So let's say class equals. So we want the LineThrough class.
So let's say class equals. So we want the LineThrough class. So we can say LineThrough, only if toDo is complete. So we say toDo.isComplete. And sorry, that should be a colon. And Svelte will take care of adding this class to the actual class list if this condition is met. So again, it should be the same thing. But we are now making use of conditional class rendering. So now to actually update the property for isComplete for our toDos whenever we check
But we are now making use of conditional class rendering. So now to actually update the property for isComplete for our to-dos whenever we check this checkbox here. So whenever we check it, we want this property to update. So again, we can make use of the v-model syntax to two-way data bind this property to the checkbox in this case. So let's do that. So our checkbox is right here. Again, let's use the v-bind syntax. So v-bind:.
Again, let's use the bind syntax. So bind :. In this case, we're binding it to the checked property. So we want it to be checked when the toDo is complete. So toDo.isComplete. Okay. Let's try that out. Save. And let's check the other ones here. And the line through does work.
So we want this to update whenever we check off to-dos. So let's work on that. So this is going to be a reactive property, as it depends on the length of the to-dos array that have not been completed. So let's do that. So let's go to our script. Let's add it right here. Let's put it here. And again, the syntax for that is $:. Let's name it remainingToDos.
And again, the syntax for that is $: remainingToDos. And we want to filter the toDos. So say toDos.filter. We want to grab the toDos that are not complete. So toDo, not toDo.isComplete. And we want the length of that. So .length. And that should do it. Let's save that.
And that should do it. Let's save that. And let's make use of that in our template. So items remaining. Let's put it right in here. Remaining to-dos. And hopefully that works. Save that. And it does seem to work. One.
Bulk Actions and Cleanup13:43
And it does seem to work. One. Zero. Okay. Now let's work on this check all button. So we want to check all the to-dos that are not checked when we press this button. Let's go ahead and make a method for that. I'm not sure why I have it as a div here. Should be a button. Change that.
Should be a button. Change that. And let's add a click handler on this. So let's say onClick equals, let's say checkAllToDos. Sorry, that should be curly braces. Okay, so let's go ahead and define that. Let's put it underneath here. checkAllToDos. And we just want to go through our toDos and set isComplete to true for all of them. So let's do that.
And we just want to go through our toDos and set isComplete to true for all of them. So let's do that. So again, let's reassign our toDos here. So it's reactive. And we can either use forEach or map to loop through our toDos and update the isComplete property. So I'll just make use of map here. toDos.map. Let's grab each to-do. And we just want to update the property here.
Let's grab each to-do. And we just want to update the property here. So let's say toDo.isComplete equals true. And then we have to return the to-do here. Okay, make sure we spell return correctly. Let's save that and see if it works. Let's check all. And it does seem to work. Let's also work on the clearCompleted functionality. So this button right here, which should remove any to-dos that are checked.
Let's also work on the clearCompleted functionality. So this button right here, which should remove any to-dos that are checked. So let's add that method here. Let's say clearCompleted. And that should do something similar, toDos =. So we just want to keep the toDos that are not complete. So we can use filter again, toDos.filter, toDo, and keep the ones that are not complete. So not toDo.isComplete. Let's save that. Let's make use of that in the clearCompleted button.
Let's save that. Let's make use of that in the clearCompleted button. So clearCompleted right here. And we can say onClick equals clearCompleted. Okay, let's give that a try. Save that. Let's check these two here. Let's clear those two out. And it does seem to work. So I think that's a good place to break.
Let's stop our server, say git add, git commit. This is episode two, say start to-do features, and we'll continue in the next episode.
