WEBVTT 0 00:00.970 --> 00:08.890 Currently as it is our list works in terms of all of the basic functionality. We're able to add new items, 1 00:08.950 --> 00:15.440 we're able to delete items and we're able to look at all of the items in our list. 2 00:15.760 --> 00:22.180 But there's one feature or one functionality that I would love to have for this app that we haven't 3 00:22.180 --> 00:26.630 currently implemented and it's the ability to have multiple lists 4 00:26.680 --> 00:27.240 right? 5 00:27.260 --> 00:30.150 There is no fun just having a single is to work off. 6 00:30.220 --> 00:36.280 So what if we were able to instead of going to the home page which is our default list what if we were 7 00:36.280 --> 00:43.480 able to just write /work and head over to the worklist and be able to see the items there. 8 00:43.480 --> 00:48.100 And what if we could create new lists on the fly like I wanted to create a home list, 9 00:48.220 --> 00:55.600 so if I type in the web address /home then I wanted to create a brand new page without me having 10 00:55.600 --> 01:02.890 to define all of the get and the post routes. We can use what we learn about express route parameters 11 01:03.010 --> 01:04.410 to do this. 12 01:04.420 --> 01:13.720 Express allows us to use route parameters to create dynamic routes. And so as a challenge I want you 13 01:13.720 --> 01:23.290 to delete this get route and instead create a dynamic route based on the route parameters so that if 14 01:23.290 --> 01:33.580 I go to localhost:3000/Home or /Work I should be up to print 15 01:33.910 --> 01:43.510 this last part of the URL inside the app.get. Again as a reminder this is what Express route parameters 16 01:43.510 --> 01:44.560 look like. 17 01:44.560 --> 01:45.960 We have a colon 18 01:46.240 --> 01:53.500 and then we have a parameter name and then inside the callback we get Access req.params. that 19 01:53.500 --> 01:54.470 parameter name. 20 01:54.520 --> 01:59.240 And this will equal the value that the user has typed in here. 21 01:59.440 --> 02:05.310 Pause the video and try to complete this challenge. 22 02:05.400 --> 02:08.650 So let's begin by creating our route. 23 02:08.730 --> 02:12.440 Maybe we'll create it just after the app.get up here. 24 02:12.810 --> 02:20.730 So I'm going to write app.get and instead providing a hardcoded route like /Work or 25 02:20.730 --> 02:21.960 /Home, 26 02:22.020 --> 02:29.700 I'm just going to write /: and then I'm going to call it customListName. 27 02:30.240 --> 02:35.800 And this is going to again accept a callback request and response. 28 02:36.090 --> 02:46.770 And then inside my callback I'm going to log req.params.customListName. 29 02:46.880 --> 02:53.920 So now let's hit save and go into our browser and I'm going to try and run this again. 30 02:53.970 --> 02:55.550 Localhos:3000 31 02:55.550 --> 02:57.310 /Home 32 02:57.460 --> 03:06.820 and now if I go into my console you can see I now have that part at the end here logged in my console. 33 03:06.960 --> 03:15.510 So I could change that to say work and if I go ahead and hit enter, then you can see I now get work logged 34 03:15.510 --> 03:16.300 in here. 35 03:16.350 --> 03:17.770 So far so good. 36 03:19.440 --> 03:25.760 Now instead of logging that param let's go ahead and save it into a constant and let's call that custom 37 03:25.770 --> 03:34.770 ListName. So customListName equals req.params.customListName and that comes from whatever 38 03:34.770 --> 03:42.610 it is that the user enters after the forward slash.Now that we have access to the name of the new list 39 03:42.730 --> 03:50.140 well we get to use it to create a new document and that document is going to have a slightly different 40 03:50.140 --> 03:52.870 schema than what items had. 41 03:52.950 --> 03:59.500 So right below where we have our default items I'm going to create a new schema and this one is going 42 03:59.500 --> 04:06.350 to be called listSchema. And this is going to take two fields: 43 04:06.350 --> 04:09.810 one is the name of the list which will be a string 44 04:09.950 --> 04:13.950 and the second is going to be an array of items. 45 04:14.120 --> 04:21.800 So the name of the field is going to be items and the value of the field is going to be an array of 46 04:21.980 --> 04:25.540 itemSchema based items. 47 04:25.550 --> 04:32.440 So now what we're saying is for every new list that we create the list is going to have a name and it's 48 04:32.450 --> 04:37.840 going to have an array of item documents associated with it as well. 49 04:39.360 --> 04:43.110 The next thing to do as always is to create our Mongoose model. 50 04:43.140 --> 04:51.330 This is going to be a constant called list and it's going to be equal to mongoose.model and then 51 04:51.330 --> 04:57.990 we're going to specify the singular version of our collection which is going to be called a list. 52 04:58.080 --> 05:02.060 And we're going to specify the schema which is listSchema. 53 05:02.830 --> 05:06.320 And make sure that you haven't got any typos like I have here 54 05:06.390 --> 05:10.410 "mongoose.mode" which should be "mongoose.model". 55 05:10.560 --> 05:17.880 So now that we've created our list model from our listSchema, then we're ready to create new list documents 56 05:17.970 --> 05:26.310 based off this model. And we're going to do that when a user tries to access a customListName. Inside 57 05:26.310 --> 05:26.850 this route 58 05:26.850 --> 05:33.330 I'm going to create a new list and this is going to be created based off our list model. 59 05:34.020 --> 05:36.240 And I have to fill in the two fields: 60 05:36.330 --> 05:42.440 one is the name of the list which is simply going to be whatever the user typed into the route. 61 05:42.510 --> 05:48.420 So if they said /Work or /Home then that's going to be the list name, 62 05:48.480 --> 05:50.630 so I'm going to put a customListName here. 63 05:51.030 --> 05:55.560 And then the second field is going to be the items. 64 05:56.160 --> 06:00.590 And this should accept an array of list items. 65 06:00.690 --> 06:07.230 And so when we create a new list that is a custom list we're going to give it the name based off the 66 06:07.230 --> 06:09.450 path that the user tried to access 67 06:09.450 --> 06:16.640 and then for the items we're simply going to start off with the same default items as we created previously. 68 06:16.920 --> 06:24.510 So previously when we made our default list we created 3 item documents and we packaged them all into 69 06:24.630 --> 06:25.570 an array. 70 06:25.740 --> 06:32.110 So we can now reuse this array to populate our custom lists. 71 06:32.130 --> 06:39.310 So inside here the items for my new list are simply going to be the default items. 72 06:39.510 --> 06:47.700 Now that we've created our new list document then all we have to do is call list.save to save that into 73 06:47.760 --> 06:50.580 the lists collection. 74 06:50.590 --> 06:58.300 Now if we save our app.js and we head over to our browser and we try to access for example 75 06:58.300 --> 07:06.700 localhost:3000/Home and we hit enter, then if we go into our Mongo shell and we 76 07:06.700 --> 07:14.260 just say "show collections" then you can see we now have a new collection and that collection is a collection 77 07:14.260 --> 07:15.350 of lists. 78 07:15.400 --> 07:24.220 So let's say "db.lists.find" and you can see that we have a single document inside our lists collection 79 07:24.580 --> 07:31.420 which has the name of home which corresponds to this part that we entered using the route parameters 80 07:31.930 --> 07:37.050 and then it has an array of items which correspond to our default items. 81 07:37.090 --> 07:38.430 "Welcome to your todolist! 82 07:38.440 --> 07:42.650 Hit the + button and then hit this to delete the item". 83 07:42.650 --> 07:44.460 So so far so good. 84 07:44.470 --> 07:46.760 That was pretty successful. 85 07:46.760 --> 07:48.400 Now here's the problem. 86 07:48.620 --> 07:55.420 When a user accesses local host or whatever the website domain will be /Home 87 07:55.610 --> 07:59.690 then we'll create a new list with that name home 88 07:59.700 --> 08:00.210 right? 89 08:00.530 --> 08:03.390 But we don't really want a whole bunch of them. 90 08:03.530 --> 08:08.140 What if it users already created the list and they simply want to access it? 91 08:08.150 --> 08:16.480 So for example if I head back over here and we stop this and try to head over to Home again then if 92 08:16.490 --> 08:23.180 we check our Mongo shell and we try to run "db.list.find" then you can see we now actually 93 08:23.180 --> 08:26.630 have two lists both called home 94 08:26.630 --> 08:27.380 right? 95 08:27.410 --> 08:29.020 So this is not what we want. 96 08:29.030 --> 08:35.980 We don't want to create a new list with the same name every time the user tries to access it. How can 97 08:35.980 --> 08:37.860 we solve this with code? 98 08:38.020 --> 08:46.270 Well, we have to check to see if a list with that name already exists in our collection of lists. And 99 08:46.270 --> 08:49.020 if it does then we're just going to display it 100 08:49.150 --> 08:53.710 but if it doesn't then we'll create a new one using the default items. 101 08:55.420 --> 09:04.060 So as a challenge, I want you to use the Mongoose method called findOne to find within our lists collection 102 09:04.390 --> 09:10.240 whether if there's a list that has the same name as the one that the user is currently trying to access. 103 09:10.900 --> 09:17.900 And if there is, then we're just going to log "exists" and if it doesn't exist then we'll log "doesn't exist". 104 09:17.920 --> 09:21.190 So pause the video and try to complete that challenge. 105 09:24.420 --> 09:24.690 All right. 106 09:24.690 --> 09:34.480 So just above where we create our list we're going to call findOne on our list model. And the condition 107 09:34.480 --> 09:36.160 we're going to give it is 108 09:36.160 --> 09:40.910 find me a list inside the collection of lists that has the name 109 09:40.960 --> 09:45.080 that's the same as the one that the user is currently trying to access, 110 09:45.280 --> 09:54.530 so custom list name. And once you've completed that then we'll have the callback function with error 111 09:54.680 --> 09:57.060 and foundList. 112 09:57.110 --> 10:00.410 So that means if there was an error then it'll print it, 113 10:00.430 --> 10:04.790 but if there wasn't then we should be have to tap into what was found. 114 10:04.790 --> 10:14.910 So we can say if there were no errors, then in that case we're going to check to see if there is or there 115 10:14.940 --> 10:17.510 isn't a foundList. 116 10:17.520 --> 10:24.180 Now it's important to differentiate between findOne and the one that we used previously which is find 117 10:24.240 --> 10:31.050 all essentially because this method is going to give us an array back as the result. 118 10:31.200 --> 10:35.330 And that's why we have to check to see if the array had a length of 0 119 10:35.370 --> 10:37.840 namely it had no items in it. 120 10:37.860 --> 10:39.300 It was an empty array. 121 10:39.630 --> 10:44.580 But in this case what we get is an object back because we're saying findOne 122 10:44.580 --> 10:49.010 so you'd only return one document if it is found. 123 10:49.110 --> 10:51.290 So we can't check it's length. 124 10:51.450 --> 10:54.840 But instead we can simply check to see if it exists or not 125 10:54.840 --> 10:55.550 right? 126 10:55.620 --> 10:57.510 If foundList doesn't exist 127 10:57.510 --> 11:02.580 well then in that case we'll log "Doesn't exist". 128 11:03.150 --> 11:11.760 But otherwise then it will log "Exists." Now let's give that a go 129 11:11.950 --> 11:13.810 and let's go into 130 11:16.520 --> 11:21.300 our website and we try to access localhost:3000/Home 131 11:21.560 --> 11:24.750 Let's hit enter and see what we get in our console. 132 11:24.770 --> 11:27.950 So let's switch back to this tab and it says "Exists". 133 11:28.280 --> 11:33.260 But what if we tried some sort of new one that we've obviously not made yet and 134 11:33.260 --> 11:36.420 hit enter and "Doesn't exist". 135 11:36.440 --> 11:36.830 Great! 136 11:36.860 --> 11:39.350 So our code seems to be working. 137 11:39.350 --> 11:46.120 So now instead of console logging we're going to go ahead and implement the code that we need. Here 138 11:46.130 --> 11:50.710 I'm going to write a comment saying this should be the path where we create a new list. 139 11:51.140 --> 11:57.380 And down here instead of this console log I'm going to have a comment that says this is a path where we should 140 11:57.470 --> 12:01.820 show an existing list. 141 12:01.820 --> 12:08.870 So if there were no list that were found that have the same name then we're going to create a new list. 142 12:08.990 --> 12:12.870 And the part of our code which does that is of course this section. 143 12:12.890 --> 12:19.860 So we'll just cut that and paste it into the IF and then we have the ELSE statement. 144 12:20.040 --> 12:24.020 So show an existing list if it already exists here. 145 12:24.180 --> 12:27.640 We're going to use that found list that we tapped into 146 12:27.930 --> 12:30.480 and we've really checked that it's definitely not nil, 147 12:30.480 --> 12:31.920 it definitely exists. 148 12:31.920 --> 12:39.130 So what we can do is we can call res.render and we're going to render our list.ejs 149 12:39.480 --> 12:46.080 and then the second parameter we're going to pass in is going to be the list title and also the items, 150 12:46.330 --> 12:48.610 so let's just copy that in here. 151 12:48.810 --> 12:53.770 Now the list title is no longer going to be a static word like today. 152 12:54.030 --> 12:57.250 Instead it's going to be the customListName right? 153 12:57.330 --> 13:05.590 So we could tap into this found list and we can say .name to tap into its name field. 154 13:05.910 --> 13:13.260 And for the items we do something quite similar. We say foundList.items 155 13:13.260 --> 13:20.230 and so now we'll tap into the name property and the items property and we'll send that over to list 156 13:20.250 --> 13:23.550 .ejs to populate that page. 157 13:23.550 --> 13:31.800 So now let's hit save and let's head back into our localhost:3000 which still works as it should. 158 13:31.800 --> 13:36.420 And this one of course has the default list with the static name of today. 159 13:36.600 --> 13:40.200 But let's go ahead and access our home list. 160 13:40.650 --> 13:46.830 So we've now got a home list and what if we try to create a new one, say a worklist. 161 13:51.760 --> 13:58.330 Well it seems like the list got created because if we check in our Mongo shell then you can see there's 162 13:58.330 --> 14:04.210 a whole bunch of stuff that got created but the last document that we added was this one with a name 163 14:04.300 --> 14:05.570 of work. 164 14:05.800 --> 14:10.780 If you wanted to clear out a particular collection because it's kind of gathering dust and it's got 165 14:10.780 --> 14:16.810 data from previous testing, then all you have to do is to make sure that you're inside the correct database, 166 14:16.810 --> 14:20.340 so I am, I'm using todolistDB. 167 14:20.890 --> 14:24.660 And then here we can show collections. 168 14:24.680 --> 14:35.810 So we've got items and lists and I can say "db.lists.drop" and this will wipe out my lists collection 169 14:36.010 --> 14:44.060 so that if I say "show collections" again, lists no longer exist. Let's head back to our web page and access 170 14:44.180 --> 14:46.340 home again. 171 14:46.340 --> 14:54.860 So that should now be created inside here and "show collections" should now list list and db.lists. 172 14:54.890 --> 14:59.750 find should now list a single document with name of home. 173 14:59.780 --> 15:04.860 And if I change that to work and hit enter then 174 15:04.910 --> 15:10.020 now I should have two documents: one called home and one called work. 175 15:10.160 --> 15:13.770 But why are they not automatically showing up in here? 176 15:14.240 --> 15:21.680 Well when we create a new list we fall into this IF block and all we do at the end of it is we just 177 15:21.680 --> 15:26.100 call list.save and then we're done with it. We're leaving the user hanging right? 178 15:26.330 --> 15:34.340 So we're going to use our neat trick of using res.redirect and we're going to redirect back to 179 15:34.340 --> 15:42.090 the current route which remember, is not just the route route but it's /customListName. 180 15:42.350 --> 15:48.890 But luckily we already have access to that inside this IF statement so we can say redirect to / 181 15:49.250 --> 15:54.180 and then we're going to concatenate the customListName. 182 15:54.230 --> 16:02.580 Now if we head back into our website and we tried to create a new list say "School" and hit enter, 183 16:02.600 --> 16:08.300 you can see we are redirected to that route and we've now got our list showing up here.