Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:00,480 --> 00:00:04,410
So now the functionality for our ToDo list
2
00:00:04,410 --> 00:00:07,500
version 2 is almost complete.
3
00:00:07,500 --> 00:00:13,770
We're able to access our default list on the home page and we can add new items here
4
00:00:14,070 --> 00:00:16,230
which gets added to our database.
5
00:00:16,230 --> 00:00:22,450
We can delete them from our database and we can also create custom lists
6
00:00:22,470 --> 00:00:24,620
for example one called shopping
7
00:00:25,050 --> 00:00:25,310
right?
8
00:00:25,310 --> 00:00:31,890
So we now have a new list with three default items and we can write something like "Buy milk" and it will get
9
00:00:31,950 --> 00:00:36,540
added to that particular list and all of this gets persisted.
10
00:00:36,540 --> 00:00:43,920
So whatever it is that we decide to save into the home list or into the worklist then they always stay
11
00:00:43,920 --> 00:00:47,840
where they're meant to be associated with that particular list.
12
00:00:48,330 --> 00:00:55,050
So the last thing that we need to do is we need to be able to delete these items in our custom lists
13
00:00:55,590 --> 00:01:04,950
because at the moment when I check this off then it somehow redirects me back to my home page instead
14
00:01:05,010 --> 00:01:09,910
of actually deleting the item that I wanted from that custom list.
15
00:01:09,930 --> 00:01:11,160
You can see it's still there right?
16
00:01:11,170 --> 00:01:14,440
So why is this?
17
00:01:14,710 --> 00:01:22,480
Well, if you take a look inside our list.ejs at the moment the way that we're implementing the delete
18
00:01:22,480 --> 00:01:30,850
functionality is through the use of this form. And this form makes a post request to the /delete
19
00:01:30,850 --> 00:01:40,750
route and it passes over the item id that the user wanted to delete and the form gets triggered when
20
00:01:40,780 --> 00:01:43,390
one of the checkboxes gets clicked.
21
00:01:43,390 --> 00:01:47,360
So here's a problem. In that route
22
00:01:47,360 --> 00:01:55,790
we only look for all of the items but we don't currently check which list the item is from in order
23
00:01:55,790 --> 00:01:59,130
to delete it from the correct list.
24
00:01:59,150 --> 00:02:05,840
So the first thing we need is that when we tap into this route we need two pieces of information: the
25
00:02:05,870 --> 00:02:13,880
ID of the checked item but we also need to know which list that item came from. In this form
26
00:02:13,880 --> 00:02:20,180
there isn't a submit button right? Where we can put in our list title and pass that over when the form
27
00:02:20,180 --> 00:02:21,650
gets submitted.
28
00:02:21,650 --> 00:02:27,770
There's no other input other than our checkbox which already has a value and we definitely need that
29
00:02:27,770 --> 00:02:30,300
value of the item ID.
30
00:02:30,710 --> 00:02:31,910
What can we do here?
31
00:02:32,830 --> 00:02:39,950
Rather handily in the list of inputs that we get from HTML, there's one which has a type of
32
00:02:40,000 --> 00:02:41,150
hidden.
33
00:02:41,260 --> 00:02:48,250
And this allows us to include data that can't be seen or modified by users when a form is submitted.
34
00:02:48,280 --> 00:02:57,240
For example the id of the content or in our case the list name. So inside here just before the form
35
00:02:57,270 --> 00:02:57,870
ends,
36
00:02:57,870 --> 00:03:08,710
I'm going to add a new input and this input is going to have a type of hidden. And it's also going to
37
00:03:08,710 --> 00:03:15,340
have a name so that I can refer to it when I look at my req.body and the name for this is going
38
00:03:15,340 --> 00:03:18,300
to be called just listName.
39
00:03:18,490 --> 00:03:20,720
And finally it's going to have a value
40
00:03:20,800 --> 00:03:23,500
and this is where the neat part comes in.
41
00:03:23,500 --> 00:03:26,750
We're going to use that EJS tag again
42
00:03:27,070 --> 00:03:34,860
and inside here we're going to insert that listTitle that we already have access to.
43
00:03:35,160 --> 00:03:42,930
And now we can close off our inputs and make sure that we add a closing input tag because it's not
44
00:03:42,960 --> 00:03:44,820
a self closing tag,
45
00:03:44,970 --> 00:03:47,840
these inputs.
46
00:03:47,860 --> 00:03:56,260
So now if we hit save and we head back to our app.js in our post to our delete route we can now
47
00:03:56,290 --> 00:04:04,030
check to see what is the value of that listName. So we can create a new constant and we can call it
48
00:04:04,030 --> 00:04:05,420
list name.
49
00:04:06,340 --> 00:04:15,460
And we're going to set it to equal req.body.listName. And just check to make sure that is
50
00:04:15,460 --> 00:04:18,070
the same as it got here.
51
00:04:18,399 --> 00:04:20,260
So yep! Looks good.
52
00:04:20,260 --> 00:04:27,010
So the next thing we need to do is we're going to again use an IF statement to check to see if we are
53
00:04:27,310 --> 00:04:35,710
making a post request to delete an item from the default list where the listName is today or if we're
54
00:04:35,710 --> 00:04:44,680
trying to delete an item from a custom list. We're saying if listName is equal to today then that means
55
00:04:44,770 --> 00:04:49,750
we're on the default list and we can do everything as we did previously.
56
00:04:49,750 --> 00:04:56,150
So we'll just cut and paste that into that if block, but what about the else block?
57
00:04:56,290 --> 00:05:00,120
Well this is the case where the list name is not today
58
00:05:00,460 --> 00:05:06,520
so that delete request is actually coming from a custom list.
59
00:05:06,560 --> 00:05:14,060
In this case we need to be able to find the list document that has the current listName and then we
60
00:05:14,060 --> 00:05:20,820
need to update that list to remove the checked item with that particular ID.
61
00:05:21,050 --> 00:05:28,700
Now because inside our list document there's an array of item documents
62
00:05:28,700 --> 00:05:36,290
then it's actually a little bit more complex because we basically have to find an item inside this array.
63
00:05:36,320 --> 00:05:42,860
We have to basically trawl through this array and find an item with a particular ID and then remove
64
00:05:42,890 --> 00:05:46,750
the entire item from the array.
65
00:05:46,760 --> 00:05:48,310
There's a few ways of doing this.
66
00:05:48,350 --> 00:05:53,500
You can of course use FOR loops and use the Javascript filter method,
67
00:05:53,660 --> 00:05:56,590
but let's see if there's actually a simpler way.
68
00:05:58,530 --> 00:06:08,430
If we head over to Google and we simply just search for "mongoose remove document from array". That seems
69
00:06:08,880 --> 00:06:11,680
pretty much like what we've been trying to do
70
00:06:11,700 --> 00:06:12,360
right?
71
00:06:12,690 --> 00:06:17,420
Let's see what the first non-ad Stack Overflow post says.
72
00:06:17,910 --> 00:06:24,750
So in this case they're saying you want to delete an array element in a document and then save.
73
00:06:24,750 --> 00:06:29,140
So that sounds kind of similar to what we wanted to do.
74
00:06:29,460 --> 00:06:37,670
If we look at the answer, the first answer says that you can do that directly in MongoDB. And you
75
00:06:37,670 --> 00:06:45,260
can use one of the pull or pullAll operators to remove an item from the array.
76
00:06:45,260 --> 00:06:47,950
Now we have a bit of a hint to go on.
77
00:06:47,990 --> 00:06:52,190
So we need to use this thing pull or pullAll.
78
00:06:52,360 --> 00:06:59,530
So let's search the MongoDB docs and we're going to look for this pull operator to find out a bit
79
00:06:59,530 --> 00:07:00,970
more information about it.
80
00:07:02,420 --> 00:07:11,210
So it tells you that the pull operator removes from an existing array all instances of a value or values
81
00:07:11,480 --> 00:07:18,480
that match a specified condition. And they've shown you an example of how you can use this.
82
00:07:18,620 --> 00:07:28,520
So we can use this along with the Mongoose method which is called findOneAndUpdate to combine these
83
00:07:28,520 --> 00:07:35,000
two together in order to achieve what it is that we need because with Mongoose alone or with Javascript
84
00:07:35,010 --> 00:07:38,870
alone we can actually get this really neat pull functionality.
85
00:07:38,960 --> 00:07:45,260
We have to use something that's fundamental to MongoDB. And all the operators that's preceded by a
86
00:07:45,260 --> 00:07:51,800
dollar sign comes from MongoDB. And you can see if you scroll down there's actually a whole bunch of
87
00:07:51,890 --> 00:07:57,860
other operators you can use as well but this one is far more efficient than if we tried to loop through
88
00:07:57,860 --> 00:08:03,440
all of the items in our array, reading each of them and then removing them through the filter method that
89
00:08:03,440 --> 00:08:04,830
Javascript gives us.
90
00:08:04,940 --> 00:08:10,460
This is just a slightly more efficient way of getting to the end result which we found through just
91
00:08:10,460 --> 00:08:13,120
doing a quick Google search.
92
00:08:13,170 --> 00:08:14,610
This is what the mongoose
93
00:08:14,610 --> 00:08:15,520
findOne
94
00:08:15,530 --> 00:08:23,100
AndUpdate syntax looks like. We first specify the model which corresponds to the collection that we want
95
00:08:23,100 --> 00:08:25,710
to find one and update from,
96
00:08:25,890 --> 00:08:27,960
and then we call findOneAndUpdate
97
00:08:28,230 --> 00:08:30,960
and finally we provide three things:
98
00:08:30,990 --> 00:08:33,720
one is the filter conditions,
99
00:08:33,720 --> 00:08:35,500
what do we want to find right?
100
00:08:35,520 --> 00:08:37,030
This is the query.
101
00:08:37,289 --> 00:08:40,659
And then the second one is well, what do you want to update?
102
00:08:40,770 --> 00:08:47,610
And the final thing is a callback where we get the results of what we found based on those conditions.
103
00:08:49,150 --> 00:08:54,340
So in our case the conditions we've already seen before and the callback we've really seen before.
104
00:08:54,460 --> 00:08:58,670
But in this part where we have to provide the updates, how do we actually do it?
105
00:08:58,810 --> 00:09:00,650
Well let's break it down a little bit more.
106
00:09:00,910 --> 00:09:02,950
We want to use the pull operator.
107
00:09:03,070 --> 00:09:11,470
So inside there, we have to specify the $pull operator as a key and then the value has to be the field
108
00:09:11,470 --> 00:09:13,020
that we want to pull from,
109
00:09:13,210 --> 00:09:15,810
so this has to be an array of something.
110
00:09:15,910 --> 00:09:23,050
In our case is an array of items. And then we have to provide a value for that field, which item in tha
111
00:09:23,110 --> 00:09:24,170
array of items.
112
00:09:24,250 --> 00:09:26,240
do we actually want to pull?
113
00:09:26,380 --> 00:09:30,050
So the final syntax looks something like this.
114
00:09:30,430 --> 00:09:33,670
And it's a little bit complex which is why I broke it down.
115
00:09:33,670 --> 00:09:37,980
But essentially we're saying we want to pull from a particular array
116
00:09:38,230 --> 00:09:45,970
and the way that we're going to find the item inside that array is through its ID or through its name
117
00:09:46,060 --> 00:09:48,170
or whatever it is you want to choose.
118
00:09:48,370 --> 00:09:50,160
And then we have to provide the value.
119
00:09:50,200 --> 00:09:53,790
So let's understand this a little bit better by seeing it in action.
120
00:09:55,330 --> 00:10:02,140
Inside our delete route and inside this ELSE block where we've checked that the list that the delete request
121
00:10:02,140 --> 00:10:04,530
came from is not our default list,
122
00:10:04,570 --> 00:10:13,090
we're going to tap into our list model and we're going to call findOneAndUpdate and just make sure
123
00:10:13,090 --> 00:10:14,590
you don't have any typos in there.
124
00:10:16,040 --> 00:10:18,890
And then we have to specify three things right?
125
00:10:18,890 --> 00:10:20,970
The first is the condition,
126
00:10:21,020 --> 00:10:24,140
so which list do you want to find?
127
00:10:24,470 --> 00:10:26,390
And we're only going to get one back,
128
00:10:26,390 --> 00:10:29,440
remember. This is how findOne works.
129
00:10:29,450 --> 00:10:32,750
The second thing is what updates do we want to make?
130
00:10:33,050 --> 00:10:36,200
And the last thing is simply just a callback.
131
00:10:36,200 --> 00:10:40,210
Now in the first part this is quite easy.
132
00:10:40,280 --> 00:10:48,200
The list that we want to find has to have a name that corresponds to this listName constant that we
133
00:10:48,200 --> 00:10:49,480
got from our list.
134
00:10:49,500 --> 00:10:51,830
ejs. Let's put that in there.
135
00:10:51,830 --> 00:10:58,220
This is going to be the name of our custom list. Now that we found that document that corresponds to
136
00:10:58,220 --> 00:10:59,540
the customer list,
137
00:10:59,570 --> 00:11:02,020
how are we going to update it?
138
00:11:02,540 --> 00:11:10,190
Well first we need to use the pull operator, and then we're going to specify something that we want to
139
00:11:10,190 --> 00:11:18,890
pull from and here we have to provide the name of the array inside this list that we found and that
140
00:11:18,890 --> 00:11:22,140
name is of course going to be items.
141
00:11:22,160 --> 00:11:27,410
This is the only thing that's an array inside our list document.
142
00:11:27,420 --> 00:11:31,970
So now we can say pull from the items array.
143
00:11:32,010 --> 00:11:36,950
Now how do we know which item out of all of the items we want to pull?
144
00:11:37,140 --> 00:11:44,540
Well here's another further set of curly braces where we provide the query for matching the item.
145
00:11:44,640 --> 00:11:51,600
The query we're going to make is we're going to pull the item which has an ID that corresponds to the
146
00:11:51,630 --> 00:11:53,830
checkedItemId.
147
00:11:54,300 --> 00:11:56,850
So we're going to put that in there.
148
00:11:57,390 --> 00:12:05,340
And now this three layered cake is finally complete and this is the entirety of our update statement
149
00:12:05,830 --> 00:12:13,540
where we pull from our items array an item that has an ID that corresponds to our checkedItemId.
150
00:12:13,590 --> 00:12:15,940
And finally we're ready to write our callback.
151
00:12:15,990 --> 00:12:23,550
So again it's going to be a callback that gives you an error and a found list because in this case when we're
152
00:12:23,550 --> 00:12:29,910
calling findOneAndUpdate the find one corresponds to finding a list.
153
00:12:29,910 --> 00:12:39,680
Now that we've found the list and we've updated it then if there are no errors we can simply res.
154
00:12:39,910 --> 00:12:48,130
redirect. And we're going to redirect again to that custom list path
155
00:12:48,150 --> 00:12:54,600
so it's going to be "/" + listName.
156
00:12:54,810 --> 00:12:59,090
We're finally ready to save and test our app.
157
00:12:59,220 --> 00:13:06,840
So if we're on the work route, let's just refresh that page, and I decided to delete this item.
158
00:13:06,840 --> 00:13:13,550
Hit this to delete an item, then I click on it it gets deleted I get redirected back to the same list.
159
00:13:13,710 --> 00:13:15,960
Let's delete another one just to be sure.
160
00:13:16,020 --> 00:13:18,150
Again I get redirected to the same list.
161
00:13:18,180 --> 00:13:24,320
So now we're able to create custom lists and we get to add items
162
00:13:26,900 --> 00:13:35,720
and we get to delete items from our custom list as well as adding items to our default list and deleting
163
00:13:35,720 --> 00:13:36,940
them there as well.
164
00:13:38,560 --> 00:13:46,120
Now there's just one last niggling thing which is when we create our route parameters as we saw previously
165
00:13:46,420 --> 00:13:52,120
it actually differentiates between a lower case work and a upper case work.
166
00:13:52,120 --> 00:13:59,170
So in this case I'm trying to access localhost:3000/home with a lowercase "h" and
167
00:13:59,200 --> 00:14:04,850
you can see here I get this list that has a title of lowercase home.
168
00:14:04,900 --> 00:14:11,530
So let's go ahead and add a new item, "Buy sofa" to our home list.
169
00:14:11,530 --> 00:14:18,990
Now if I switch over to /Home, then it's a completely different list right?
170
00:14:19,000 --> 00:14:23,620
And that's crazy because the user probably wanted the same list.
171
00:14:23,650 --> 00:14:33,470
How can we solve this? What if we always wanted the capitalized version of the list in our title?
172
00:14:33,530 --> 00:14:41,180
How can we change whatever inputs that the user makes into that custom listName and change that string
173
00:14:41,270 --> 00:14:42,880
into a title case?
174
00:14:43,040 --> 00:14:46,100
So always capitalize the first letter.
175
00:14:46,670 --> 00:14:49,150
There's again lots of ways of doing this
176
00:14:49,340 --> 00:14:53,290
but the easiest way is just to simply use trusty Lodash.
177
00:14:53,570 --> 00:15:00,500
So let's go ahead and exit out of our server and let's npm install Lodash.
178
00:15:00,530 --> 00:15:05,980
Now while that's doing its thing, let me just show you the documentation for Lodash.
179
00:15:06,110 --> 00:15:14,770
If you scroll all the way down to the strings section you can see that we tried out kebab case, lower
180
00:15:14,770 --> 00:15:16,840
case, lower case first,
181
00:15:17,140 --> 00:15:23,890
but there's also this one called capitalize. And if you read through the docs you'll see that this one
182
00:15:23,980 --> 00:15:30,240
converts the first character of a string to uppercase and the remaining to lowercase.
183
00:15:30,250 --> 00:15:37,420
So that means even if you write all caps FRED or all lowercase fred, whatever it may be, it'll always just
184
00:15:37,420 --> 00:15:44,770
capitalize that string and only change the first letter to uppercase and all the rest to lowercase. We
185
00:15:44,770 --> 00:15:52,330
can add Lodash into our app with the Lodash convention which is a underscore and we're going to let it
186
00:15:52,390 --> 00:15:57,170
equal require "lodash".
187
00:15:57,250 --> 00:16:04,940
So now whenever we need some functionality we can just tap into it using that underscore. And the place
188
00:16:04,940 --> 00:16:09,030
where we need it is inside this route.
189
00:16:09,050 --> 00:16:14,390
So instead of setting the customListName to just simply whatever it is that the user typed in here,
190
00:16:14,780 --> 00:16:22,340
we're going to modify it to make it capitalized. And we can call that method by simply saying _
191
00:16:22,520 --> 00:16:29,800
.capitalize and then inside the parentheses we'll provide a string just as you can see in this example.
192
00:16:30,720 --> 00:16:37,520
Here we're going to say customListName is equal to _.capitalize
193
00:16:37,680 --> 00:16:44,820
and remember because we're working with stuff created by people in America we have to respect the spelling.
194
00:16:44,820 --> 00:16:49,570
So it's a capitalize with a "z" instead of a "s".
195
00:16:49,840 --> 00:16:58,010
So now if we hit save and we go back to our console and we restart our server with nodemon.
196
00:16:58,660 --> 00:17:05,290
Now before we test our app we first have to drop our current collection because if you check out db
197
00:17:05,290 --> 00:17:13,450
.lists.find you can see we currently have the uppercase home, the lowercase home and it's all
198
00:17:13,660 --> 00:17:14,220
a mess.
199
00:17:14,260 --> 00:17:18,650
And this is before we enabled that functionality using Lodash.
200
00:17:18,880 --> 00:17:25,460
So let's go ahead and do db.lists.drop and hit enter.
201
00:17:25,480 --> 00:17:26,920
Now that's been executed.
202
00:17:26,950 --> 00:17:31,050
So if we do db.list.find you can see it's completely empty.
203
00:17:31,050 --> 00:17:35,790
Now let's go ahead and try to navigate to localhost:3000
204
00:17:35,800 --> 00:17:39,830
/work with the lowercase "w".
205
00:17:40,120 --> 00:17:45,760
And remember that Chrome loves to auto suggest. So sometimes you might think you're going to the capital
206
00:17:45,760 --> 00:17:50,140
one but it actually automatically redirected you to the lowercase one.
207
00:17:50,140 --> 00:17:53,780
So just to be sure just click on the one that you see in here.
208
00:17:53,890 --> 00:18:04,000
So here I'm going to /work and now I'm going to add a new item "Write emails" and
209
00:18:04,030 --> 00:18:10,790
hit add. And then I'm going to change this to the capital version of work,
210
00:18:10,840 --> 00:18:11,670
hit enter.
211
00:18:11,770 --> 00:18:18,180
You can see I'm still on the same list. And it's the same thing if we change that to lowercase
212
00:18:18,220 --> 00:18:24,850
home, it'll always redirect me to the list with a capitalized name.
213
00:18:25,030 --> 00:18:30,780
Even if I decide to do something really crazy like "HOMe".
214
00:18:30,900 --> 00:18:38,920
So something that just completely messes up the casing then I still get taken to the right page.
215
00:18:38,930 --> 00:18:45,650
I hope you enjoyed building this along with me and learning how to add a database to our Node.js apps
216
00:18:45,920 --> 00:18:54,650
that will make your apps infinitely more powerful and be able to permanently store your user data. In
217
00:18:54,650 --> 00:18:55,750
the next lesson
218
00:18:55,760 --> 00:19:03,200
it's your turn to add a database to the blog website that you created earlier on and it's finally time
219
00:19:03,230 --> 00:19:06,200
to actually turn it into a real product.
220
00:19:06,200 --> 00:19:09,080
So for all of that and more, I'll see you on the next lesson.
22938
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.