1
00:00:01,749 --> 00:00:04,100
So I haven't forgotten

2
00:00:04,100 --> 00:00:06,800
about the image upload preview image,

3
00:00:06,800 --> 00:00:09,930
but I wanna actually start by outputting products here

4
00:00:09,930 --> 00:00:12,950
in a grid on this overview page

5
00:00:12,950 --> 00:00:16,239
before we finalize the Add new Product form

6
00:00:16,239 --> 00:00:18,560
and we add this image preview.

7
00:00:18,560 --> 00:00:20,930
And, therefore, let's add such a grid.

8
00:00:20,930 --> 00:00:21,980
And I'm saying grid

9
00:00:21,980 --> 00:00:24,630
because I don't just wanna have a list of products

10
00:00:24,630 --> 00:00:27,180
where we have one product below the other one,

11
00:00:27,180 --> 00:00:30,700
but instead I wanna have a grid with columns and rows.

12
00:00:30,700 --> 00:00:32,210
And with the CSS grid,

13
00:00:32,210 --> 00:00:35,440
it's really easy to create such grid layouts,

14
00:00:35,440 --> 00:00:37,743
which is why I wanna include it here.

15
00:00:38,750 --> 00:00:42,370
For this, it's time to go to the all-products.ejs file

16
00:00:42,370 --> 00:00:46,980
where I have this section for outputting a list of products.

17
00:00:46,980 --> 00:00:49,840
Here, I'm not really outputting a list of products yet,

18
00:00:49,840 --> 00:00:51,553
but that should now change.

19
00:00:52,500 --> 00:00:54,950
For this, I'll add a unordered list in there,

20
00:00:54,950 --> 00:00:56,610
could also be a ordered list,

21
00:00:56,610 --> 00:00:59,210
but the order isn't too important,

22
00:00:59,210 --> 00:01:01,140
and then in there, I wanna have list items

23
00:01:01,140 --> 00:01:03,233
with my product data.

24
00:01:04,670 --> 00:01:08,810
Now, the product data can be more or less sophisticated.

25
00:01:08,810 --> 00:01:10,390
In the end here,

26
00:01:10,390 --> 00:01:14,220
I just wanna have, let's say, an article

27
00:01:14,220 --> 00:01:15,840
for semantic reasons.

28
00:01:15,840 --> 00:01:18,110
We could also do it without that,

29
00:01:18,110 --> 00:01:23,110
but it is considered a good idea to wrap standalone items

30
00:01:23,150 --> 00:01:26,760
that could work on their own with such a article,

31
00:01:26,760 --> 00:01:30,100
and a single product is a standalone item in that list

32
00:01:30,100 --> 00:01:31,990
even though it's part of that list.

33
00:01:31,990 --> 00:01:35,450
So I'll use a article to wrap my product data.

34
00:01:35,450 --> 00:01:37,360
And then in this article,

35
00:01:37,360 --> 00:01:39,880
I, in the end, wanna have h2 tag

36
00:01:39,880 --> 00:01:42,790
with the title of the product,

37
00:01:42,790 --> 00:01:47,790
and then let's say above that, the image of the product,

38
00:01:47,860 --> 00:01:52,030
and then below that, I want to have two buttons

39
00:01:52,030 --> 00:01:55,063
that allow me to interact with that product.

40
00:01:56,160 --> 00:01:59,280
And for this, I'll actually then just add a div here

41
00:02:00,400 --> 00:02:02,970
which allows me to style these two buttons

42
00:02:02,970 --> 00:02:05,600
to sit side by side.

43
00:02:05,600 --> 00:02:08,550
And the first button will actually be an anchor tag

44
00:02:08,550 --> 00:02:13,040
which loads the detail page or the added page

45
00:02:13,040 --> 00:02:15,620
for an existing product which doesn't exist yet,

46
00:02:15,620 --> 00:02:17,170
but which we'll add soon.

47
00:02:17,170 --> 00:02:18,863
Here, I'll say View & Edit.

48
00:02:20,080 --> 00:02:24,520
And then I also wanna have, let's say, a button below that

49
00:02:24,520 --> 00:02:26,720
which says Delete.

50
00:02:26,720 --> 00:02:27,740
And we'll make sure

51
00:02:27,740 --> 00:02:30,660
that these buttons and links work correctly later.

52
00:02:30,660 --> 00:02:32,750
For the moment, I'll just add them.

53
00:02:32,750 --> 00:02:36,770
And I'll give the anchor tag a class of btn btn-alt,

54
00:02:36,770 --> 00:02:40,180
and the button will get the same classes here

55
00:02:40,180 --> 00:02:42,003
to have the proper styling.

56
00:02:43,104 --> 00:02:44,610
But speaking of styling,

57
00:02:44,610 --> 00:02:48,110
we, of course, need to work on the overall list

58
00:02:48,110 --> 00:02:50,173
and the articles in there.

59
00:02:51,130 --> 00:02:56,130
And, actually, I will outsource this article into an include

60
00:02:57,560 --> 00:03:01,280
so that here in admin/products, I'll add an includes folder,

61
00:03:01,280 --> 00:03:03,100
and in that includes folder,

62
00:03:03,100 --> 00:03:05,970
I'll add a product-item.ejs file,

63
00:03:05,970 --> 00:03:08,590
and in there I have this article,

64
00:03:08,590 --> 00:03:12,390
and I'll add a class of product-item on the article

65
00:03:12,390 --> 00:03:15,373
so that we can use this class for styling later.

66
00:03:16,750 --> 00:03:19,990
And then in all-products, in this list item,

67
00:03:19,990 --> 00:03:24,990
I just wanna include this list item EJS file,

68
00:03:25,090 --> 00:03:27,540
with include,

69
00:03:27,540 --> 00:03:29,380
and then it's in the includes folder

70
00:03:29,380 --> 00:03:33,570
which sits side by side to the all-products.ejs file here,

71
00:03:33,570 --> 00:03:38,103
and then product-item, like this.

72
00:03:40,610 --> 00:03:41,840
Now, of course, I don't just wanna have

73
00:03:41,840 --> 00:03:43,120
one list item here, though,

74
00:03:43,120 --> 00:03:46,210
but instead I wanna output multiple list items,

75
00:03:46,210 --> 00:03:48,350
and therefore we wanna loop

76
00:03:48,350 --> 00:03:50,420
through a couple of list items here

77
00:03:50,420 --> 00:03:53,220
with a for-of loop.

78
00:03:53,220 --> 00:03:55,350
We, of course, have to add some logic here,

79
00:03:55,350 --> 00:03:59,680
but that's the idea later, like this,

80
00:03:59,680 --> 00:04:02,273
and also close it like that.

81
00:04:03,120 --> 00:04:05,623
That's what we did before in the course already.

82
00:04:06,870 --> 00:04:08,920
But now, of course, we need the data

83
00:04:08,920 --> 00:04:11,220
through which we can loop here.

84
00:04:11,220 --> 00:04:14,280
And that is something we have to work on on the backend,

85
00:04:14,280 --> 00:04:16,459
in our model, to be precise.

86
00:04:16,459 --> 00:04:18,070
There, we have to add logic

87
00:04:18,070 --> 00:04:20,910
for fetching data from the database.

88
00:04:20,910 --> 00:04:25,743
For this, we can go back to our model to the product.model.

89
00:04:26,630 --> 00:04:30,760
And there, below the constructor, above the save method,

90
00:04:30,760 --> 00:04:35,070
we could add a findAll method which has to go,

91
00:04:35,070 --> 00:04:39,860
as the name suggests, of finding all the product documents.

92
00:04:39,860 --> 00:04:42,730
Now, I will add async in front of that

93
00:04:42,730 --> 00:04:44,910
because we will use async/await,

94
00:04:44,910 --> 00:04:47,010
and also static

95
00:04:47,010 --> 00:04:49,480
because this should be a so-called static method

96
00:04:49,480 --> 00:04:51,930
which I also introduced before in the course.

97
00:04:51,930 --> 00:04:54,030
The special thing about static methods

98
00:04:54,030 --> 00:04:57,350
is that you don't need to instantiate the class first.

99
00:04:57,350 --> 00:05:00,340
You don't need to create an object based on the class

100
00:05:00,340 --> 00:05:03,010
in order to use static methods.

101
00:05:03,010 --> 00:05:05,680
Instead, you can call them on the class itself.

102
00:05:05,680 --> 00:05:08,500
And it's very useful for cases like this

103
00:05:08,500 --> 00:05:12,830
where we can't create a product based on this class yet

104
00:05:12,830 --> 00:05:14,900
because we have no product data.

105
00:05:14,900 --> 00:05:17,960
We're looking for product data instead.

106
00:05:17,960 --> 00:05:19,930
And then we can just use this class

107
00:05:19,930 --> 00:05:23,580
as a logical grouping unit, so to say,

108
00:05:23,580 --> 00:05:26,400
to which we add utility methods like findAll

109
00:05:26,400 --> 00:05:29,633
that find us all the product documents in the database.

110
00:05:30,950 --> 00:05:35,090
And then in findAll, we can therefore use db.getDb

111
00:05:35,090 --> 00:05:38,430
and use the products collection as before,

112
00:05:38,430 --> 00:05:41,380
and then there, we can call find,

113
00:05:41,380 --> 00:05:44,680
like this, to find all the documents.

114
00:05:44,680 --> 00:05:47,350
If you call find like that in MongoDB

115
00:05:47,350 --> 00:05:49,220
with no parameter values,

116
00:05:49,220 --> 00:05:51,800
it will give you all the documents.

117
00:05:51,800 --> 00:05:54,883
That's what we also did before here in the Mongo Shell.

118
00:05:56,860 --> 00:06:00,080
Now, find returns a so-called cursor object

119
00:06:00,080 --> 00:06:03,520
which you could use for moving through greater datasets.

120
00:06:03,520 --> 00:06:07,050
Here, I instead wanna add toArray at the end

121
00:06:07,050 --> 00:06:10,310
to enforce the returnal of an array

122
00:06:10,310 --> 00:06:13,893
so that we get back an array of product objects in the end.

123
00:06:15,900 --> 00:06:18,600
Now, this is something we can and should await

124
00:06:18,600 --> 00:06:20,883
to get our products in the end, like that,

125
00:06:21,760 --> 00:06:25,833
and then here, I wanna return the products I got.

126
00:06:27,080 --> 00:06:29,830
And, actually, I don't wanna return them like this

127
00:06:29,830 --> 00:06:33,380
because that would be the pure documents

128
00:06:33,380 --> 00:06:35,180
which I have in the database.

129
00:06:35,180 --> 00:06:37,780
Instead, I wanna transform them.

130
00:06:37,780 --> 00:06:40,370
And that is something we can do

131
00:06:40,370 --> 00:06:42,400
with help of a utility method

132
00:06:42,400 --> 00:06:45,210
that you can execute on any array.

133
00:06:45,210 --> 00:06:46,330
No matter if it's an array

134
00:06:46,330 --> 00:06:49,660
full of products or full of strings,

135
00:06:49,660 --> 00:06:51,060
it doesn't matter.

136
00:06:51,060 --> 00:06:55,700
On any array in JavaScript, you can call a map method.

137
00:06:55,700 --> 00:06:57,850
And keep in mind that products is an array

138
00:06:57,850 --> 00:07:00,670
because we converted to an array with toArray.

139
00:07:00,670 --> 00:07:03,520
That's a utility method offered by MongoDB,

140
00:07:03,520 --> 00:07:06,003
and it ensures that we get back an array.

141
00:07:06,960 --> 00:07:11,430
On such arrays, as products is one, we can call map,

142
00:07:11,430 --> 00:07:14,900
and map takes a function, an anonymous function,

143
00:07:14,900 --> 00:07:17,513
for example, as a parameter value.

144
00:07:18,560 --> 00:07:21,740
Now, this function will be executed by JavaScript

145
00:07:21,740 --> 00:07:24,850
for every entry in that array.

146
00:07:24,850 --> 00:07:27,740
And we'll get that entry, that item,

147
00:07:27,740 --> 00:07:30,380
or in our case that product as we know,

148
00:07:30,380 --> 00:07:33,980
as a parameter in this anonymous function.

149
00:07:33,980 --> 00:07:35,800
And in this anonymous function,

150
00:07:35,800 --> 00:07:40,800
we can then return a new value which should be used instead,

151
00:07:40,900 --> 00:07:44,830
and this allows us to transform all the entries in an array

152
00:07:45,900 --> 00:07:49,510
so that I can transform an array full of products,

153
00:07:49,510 --> 00:07:52,490
full of product documents, to be precise,

154
00:07:52,490 --> 00:07:55,460
into an array full of product objects

155
00:07:55,460 --> 00:07:58,010
that look like this blueprint

156
00:07:58,010 --> 00:08:00,483
or that are based on this blueprint.

157
00:08:02,330 --> 00:08:05,270
So here I then return,

158
00:08:05,270 --> 00:08:07,070
inside of this anonymous function,

159
00:08:07,070 --> 00:08:08,650
that's where I'm returning,

160
00:08:08,650 --> 00:08:12,920
a new product now for every product document

161
00:08:12,920 --> 00:08:14,430
that I have here in the end.

162
00:08:14,430 --> 00:08:16,630
So maybe I name it such that it's clearer

163
00:08:16,630 --> 00:08:18,550
that this is a product document

164
00:08:18,550 --> 00:08:20,880
as it's coming from the database.

165
00:08:20,880 --> 00:08:25,270
And now I'm returning a new product instance instead,

166
00:08:25,270 --> 00:08:27,900
and to that constructor function here

167
00:08:27,900 --> 00:08:30,067
I pass productDocument.

168
00:08:30,938 --> 00:08:34,710
Now, that is a JavaScript object where we will find

169
00:08:34,710 --> 00:08:37,960
all the fields I'm looking for in the constructor,

170
00:08:37,960 --> 00:08:42,960
but I now convert it to a object based on this class.

171
00:08:43,030 --> 00:08:44,650
And why am I doing that?

172
00:08:44,650 --> 00:08:46,860
Well, simply so that I rebuild

173
00:08:46,860 --> 00:08:49,780
the imagePath and imageUrl fields

174
00:08:50,670 --> 00:08:54,740
because remember that those were not stored in the database

175
00:08:54,740 --> 00:08:57,910
for reasons mentioned in the previous lectures,

176
00:08:57,910 --> 00:09:00,520
but I do need them when working with the products

177
00:09:00,520 --> 00:09:03,140
in my code and in my templates.

178
00:09:03,140 --> 00:09:04,730
Therefore, I wanna transform

179
00:09:04,730 --> 00:09:07,240
all the documents fetched from the database

180
00:09:07,240 --> 00:09:09,620
into objects based on that blueprint

181
00:09:09,620 --> 00:09:13,110
so that I do have imagePath and imageUrl

182
00:09:13,110 --> 00:09:14,603
for all my products again.

183
00:09:15,570 --> 00:09:17,170
We would not have to do that

184
00:09:17,170 --> 00:09:19,870
if that data would have been stored in the database,

185
00:09:19,870 --> 00:09:21,993
but I deliberately didn't do that.

186
00:09:23,250 --> 00:09:26,200
Now that we are doing this kind of transformation here,

187
00:09:26,200 --> 00:09:29,150
I will also, by the way, add an id field here

188
00:09:29,150 --> 00:09:31,420
to this to-be created object

189
00:09:31,420 --> 00:09:33,120
which is based on productData._id,

190
00:09:35,751 --> 00:09:40,150
._id because that is the id field

191
00:09:40,150 --> 00:09:43,903
that's automatically created in the database by MongoDB.

192
00:09:45,610 --> 00:09:46,880
Here we can also see

193
00:09:46,880 --> 00:09:50,210
that it's using this special ObjectId format,

194
00:09:50,210 --> 00:09:54,040
and I wanna instead work with strings only

195
00:09:54,040 --> 00:09:56,120
so we can call toString on that

196
00:09:56,120 --> 00:10:00,080
because basically all values in JavaScript,

197
00:10:00,080 --> 00:10:03,660
including this special ObjectId data type,

198
00:10:03,660 --> 00:10:05,980
do have a toString method

199
00:10:05,980 --> 00:10:09,920
to force a conversion into a pure string.

200
00:10:09,920 --> 00:10:11,440
In case of ObjectId,

201
00:10:11,440 --> 00:10:14,480
that means that we get this string id

202
00:10:14,480 --> 00:10:16,790
instead of this special object

203
00:10:16,790 --> 00:10:19,770
which has more under-the-hood capabilities

204
00:10:19,770 --> 00:10:21,063
which we don't need here.

205
00:10:22,200 --> 00:10:25,420
So that's why I'm calling this built-in toString method

206
00:10:25,420 --> 00:10:28,010
to convert this id to a string

207
00:10:28,010 --> 00:10:31,593
which is stored in this id field in the product object.

208
00:10:33,170 --> 00:10:35,570
Of course, when a new product is created,

209
00:10:35,570 --> 00:10:37,480
this might be undefined, though,

210
00:10:37,480 --> 00:10:40,410
and calling toString would fail in that case,

211
00:10:40,410 --> 00:10:43,260
and therefore I will actually wrap this into a if check

212
00:10:43,260 --> 00:10:48,260
where I check if productData._id is actually truthy,

213
00:10:49,310 --> 00:10:52,650
which undefined would not be, for example,

214
00:10:52,650 --> 00:10:56,120
and I only extract and convert and store the id

215
00:10:56,120 --> 00:10:57,802
if I have one.

216
00:10:57,802 --> 00:11:00,010
Otherwise, I don't do anything.

217
00:11:00,010 --> 00:11:01,540
This ensures that if we create

218
00:11:01,540 --> 00:11:03,480
a product without any id data,

219
00:11:03,480 --> 00:11:04,793
we don't get an error.

220
00:11:06,450 --> 00:11:08,380
Okay, so with that, we got that.

221
00:11:08,380 --> 00:11:10,510
I'm transforming everything here.

222
00:11:10,510 --> 00:11:14,520
Now, with all that done, back in the admin-controller,

223
00:11:14,520 --> 00:11:16,130
we can get all the products

224
00:11:16,130 --> 00:11:18,693
for the getProducts controller action.

225
00:11:19,850 --> 00:11:22,500
Here, we can now also add async

226
00:11:22,500 --> 00:11:27,440
because we will use this newly added findAll method

227
00:11:27,440 --> 00:11:31,250
which returns a promise since we use async/await,

228
00:11:31,250 --> 00:11:32,950
hence I wanna use async/await

229
00:11:32,950 --> 00:11:35,650
here in the controller action as well.

230
00:11:35,650 --> 00:11:40,550
And I can get my products by awaiting Product.findAll

231
00:11:40,550 --> 00:11:42,483
using this static method.

232
00:11:43,830 --> 00:11:47,980
Now, just as before with saving, this could fail,

233
00:11:47,980 --> 00:11:51,080
so I will actually try-catch this

234
00:11:51,080 --> 00:11:54,250
to avoid any unwanted errors,

235
00:11:54,250 --> 00:11:58,430
and I'll accept that this third-parameter value next here

236
00:11:58,430 --> 00:12:01,460
to call next error

237
00:12:01,460 --> 00:12:04,590
and then return if something does go wrong

238
00:12:04,590 --> 00:12:06,193
about fetching the products.

239
00:12:07,310 --> 00:12:08,920
However, if everything succeeds,

240
00:12:08,920 --> 00:12:11,820
if we stay in the try block, if we got no error,

241
00:12:11,820 --> 00:12:13,200
then I got my products,

242
00:12:13,200 --> 00:12:17,293
and those products can now be handed here to the template.

243
00:12:18,380 --> 00:12:22,050
So now I'll hand them under a key named products,

244
00:12:22,050 --> 00:12:24,960
though that key name here is up to you,

245
00:12:24,960 --> 00:12:26,173
into that template.

246
00:12:28,110 --> 00:12:31,280
And, therefore, now with all that done,

247
00:12:31,280 --> 00:12:36,280
in all-products, in this for-of loop which was not finished,

248
00:12:36,420 --> 00:12:38,610
we can now loop through all the products,

249
00:12:38,610 --> 00:12:40,800
that's the key name I just chose,

250
00:12:40,800 --> 00:12:43,833
and get our individual product items.

251
00:12:45,070 --> 00:12:47,810
And for every item, we build such a list item

252
00:12:47,810 --> 00:12:50,683
and repeat that included product item.

253
00:12:51,730 --> 00:12:54,010
And in that product-item.ejs file,

254
00:12:54,010 --> 00:12:57,450
we can therefore then output that title

255
00:12:57,450 --> 00:13:00,383
by referring to product.title here.

256
00:13:01,590 --> 00:13:04,840
And here, I can then also output product.imageUrl

257
00:13:06,297 --> 00:13:08,853
as a source for the image,

258
00:13:08,853 --> 00:13:13,280
imageUrl because in the product.model we worked on

259
00:13:13,280 --> 00:13:14,860
a couple of seconds ago,

260
00:13:14,860 --> 00:13:18,210
I am building this imageUrl property.

261
00:13:18,210 --> 00:13:20,880
I'm deriving it dynamically.

262
00:13:20,880 --> 00:13:24,140
That's why this transformation was so important

263
00:13:24,140 --> 00:13:27,533
so that this imageUrl property exists.

264
00:13:30,360 --> 00:13:34,680
And the alt text here could then be the title again

265
00:13:34,680 --> 00:13:36,223
as a fallback text.

266
00:13:39,620 --> 00:13:42,880
I also already wanna set the link here for editing.

267
00:13:42,880 --> 00:13:46,900
That could be /admin/products/

268
00:13:46,900 --> 00:13:49,890
and then the product.id,

269
00:13:49,890 --> 00:13:53,220
though that, of course, should not be product.id like this.

270
00:13:53,220 --> 00:13:57,253
Instead, here we need to inject this dynamically like this.

271
00:13:58,640 --> 00:14:01,100
Now we got the proper product.id here.

272
00:14:01,100 --> 00:14:04,060
And it's product.id instead of product._id

273
00:14:05,480 --> 00:14:07,750
because in that model we worked on,

274
00:14:07,750 --> 00:14:11,463
I added this .id like this, not this ._id.

275
00:14:14,060 --> 00:14:15,940
Now we should also make sure

276
00:14:15,940 --> 00:14:20,240
that product is available here in product-item.

277
00:14:20,240 --> 00:14:22,810
And to ensure that this is the case,

278
00:14:22,810 --> 00:14:25,610
we can go to all-products.ejs

279
00:14:25,610 --> 00:14:28,740
and add a second-parameter value here

280
00:14:28,740 --> 00:14:31,060
to the include function

281
00:14:31,060 --> 00:14:34,870
where we now also provide an object of key-value pairs

282
00:14:34,870 --> 00:14:38,440
that will be made available to the included snippet.

283
00:14:38,440 --> 00:14:41,720
And here I wanna make a product key available

284
00:14:41,720 --> 00:14:43,170
inside of product-item

285
00:14:44,180 --> 00:14:47,023
since I'm referring to it here in all these places.

286
00:14:48,580 --> 00:14:51,010
And then the value for that product key

287
00:14:51,010 --> 00:14:53,333
is the product I have here in the loop.

288
00:14:54,330 --> 00:14:56,780
So now just as we saw it before in the course,

289
00:14:56,780 --> 00:14:57,880
we got product here.

290
00:14:57,880 --> 00:15:00,393
That's why we need it here to use its value.

291
00:15:01,990 --> 00:15:03,590
Product here on the right side,

292
00:15:03,590 --> 00:15:05,880
on the left side of the colon, on the other hand,

293
00:15:05,880 --> 00:15:06,750
is up to you.

294
00:15:06,750 --> 00:15:09,820
That should just be the key which you then use

295
00:15:09,820 --> 00:15:12,763
inside of that snippet that's being included.

296
00:15:14,760 --> 00:15:17,870
With all of that done, if you reload,

297
00:15:17,870 --> 00:15:20,850
you should see some data here.

298
00:15:20,850 --> 00:15:22,990
You won't see the image yet, though,

299
00:15:22,990 --> 00:15:24,149
and the reason for that

300
00:15:24,149 --> 00:15:27,230
is that we're not serving it statically yet.

301
00:15:27,230 --> 00:15:28,930
If we inspect this here,

302
00:15:28,930 --> 00:15:31,820
we see that there is the path to it,

303
00:15:31,820 --> 00:15:33,610
so it tries to fetch it,

304
00:15:33,610 --> 00:15:38,120
but we're not serving the uploaded images statically yet.

305
00:15:38,120 --> 00:15:40,780
And that, of course, is something we'll have to change

306
00:15:40,780 --> 00:15:43,260
before we then in the next step ensure

307
00:15:43,260 --> 00:15:46,270
that we get a proper grid styling here.

308
00:15:46,270 --> 00:15:50,350
Now, how can we serve our images statically?

309
00:15:50,350 --> 00:15:52,890
Well, app.js is the place to go.

310
00:15:52,890 --> 00:15:55,120
In app.js, we are also ensuring

311
00:15:55,120 --> 00:15:58,350
that the public folder is served statically.

312
00:15:58,350 --> 00:16:02,440
Here, I now wanna serve another folder statically.

313
00:16:02,440 --> 00:16:05,590
And we can do that with express.static, as you learned,

314
00:16:05,590 --> 00:16:09,720
but now it's the product-data folder.

315
00:16:09,720 --> 00:16:12,620
I added that product-data folder before.

316
00:16:12,620 --> 00:16:15,730
And in there, I have the images folder with the images,

317
00:16:15,730 --> 00:16:16,900
but I actually wanna serve

318
00:16:16,900 --> 00:16:19,630
the entire product-data folder statically

319
00:16:19,630 --> 00:16:22,440
so that if we had other folders or files in there,

320
00:16:22,440 --> 00:16:24,850
they would be served statically as well.

321
00:16:24,850 --> 00:16:27,020
And therefore, of course, the images folder

322
00:16:27,020 --> 00:16:29,600
will also be served statically.

323
00:16:29,600 --> 00:16:32,940
However, please note that in the product-model,

324
00:16:32,940 --> 00:16:35,670
the imageUrl which is being created

325
00:16:35,670 --> 00:16:39,140
and which is therefore being used for requesting images,

326
00:16:39,140 --> 00:16:40,790
looks like this.

327
00:16:40,790 --> 00:16:43,820
It doesn't look like product-data/images.

328
00:16:43,820 --> 00:16:47,973
Instead, it's /products/assets/images.

329
00:16:49,110 --> 00:16:51,990
Now, going for images and then some image name

330
00:16:51,990 --> 00:16:56,100
will work if we look in the product-data folder,

331
00:16:56,100 --> 00:17:01,100
but we're not serving /products/assets statically right now.

332
00:17:01,330 --> 00:17:03,680
Well, we can configure the static middleware

333
00:17:03,680 --> 00:17:06,200
to look for this kind of request

334
00:17:06,200 --> 00:17:08,563
to then serve the content of product-data.

335
00:17:09,550 --> 00:17:11,760
All we have to do is take advantage

336
00:17:11,760 --> 00:17:14,823
of this filtering mechanism I mentioned before.

337
00:17:15,790 --> 00:17:20,690
For app.use, you can define a first-parameter value,

338
00:17:20,690 --> 00:17:23,193
which is a path that acts as a filter.

339
00:17:24,099 --> 00:17:27,819
In here, we can look for /products/assets

340
00:17:28,710 --> 00:17:32,423
since that is the part with which my URL starts here.

341
00:17:33,840 --> 00:17:35,530
Now, just as we did this before

342
00:17:35,530 --> 00:17:37,390
for serving the admin routes,

343
00:17:37,390 --> 00:17:41,770
only requests that start with /products/assets

344
00:17:41,770 --> 00:17:43,750
will be handled by this middleware then,

345
00:17:43,750 --> 00:17:47,320
by this static-serving middleware in this case.

346
00:17:47,320 --> 00:17:50,710
In addition, just as with admin down here,

347
00:17:50,710 --> 00:17:52,710
this beginning of the path

348
00:17:52,710 --> 00:17:56,420
will be removed for this request now, so to say,

349
00:17:56,420 --> 00:17:59,560
and Express will look at the rest of this path

350
00:17:59,560 --> 00:18:02,883
for these middleware functions that handle that request.

351
00:18:03,890 --> 00:18:05,148
So in my case,

352
00:18:05,148 --> 00:18:08,440
that would be /products/assets, which is removed,

353
00:18:08,440 --> 00:18:10,250
and Express would then just continue

354
00:18:10,250 --> 00:18:13,623
with looking for /images and then the name of the image.

355
00:18:14,830 --> 00:18:16,200
Now, since the middleware

356
00:18:16,200 --> 00:18:19,280
which I connect to /products/assets

357
00:18:19,280 --> 00:18:22,790
tells Express that it should look for this requested data

358
00:18:22,790 --> 00:18:24,680
in the product-data folder,

359
00:18:24,680 --> 00:18:27,130
it will go into that product-data folder

360
00:18:27,130 --> 00:18:30,850
and look for images folder and then that image name,

361
00:18:30,850 --> 00:18:32,403
and this will now succeed.

362
00:18:33,530 --> 00:18:38,450
So that is how we can serve uploaded images statically

363
00:18:38,450 --> 00:18:42,000
even if we wanna go for a specific URL that should be used

364
00:18:42,000 --> 00:18:45,010
for requesting that data or these files

365
00:18:45,010 --> 00:18:46,430
that might not be the same

366
00:18:46,430 --> 00:18:49,630
as the folder structure we have on the server.

367
00:18:49,630 --> 00:18:51,250
And the advantage of this could be

368
00:18:51,250 --> 00:18:55,020
that now with the URL which is seen in the browser

369
00:18:55,020 --> 00:18:57,160
and which can be viewed by the visitors,

370
00:18:57,160 --> 00:18:58,610
we don't give any hints

371
00:18:58,610 --> 00:19:01,890
about the folder structure we have on the server.

372
00:19:01,890 --> 00:19:04,640
It wouldn't be horrible if we gave some hints,

373
00:19:04,640 --> 00:19:07,123
but I wanted to show you this alternative.

374
00:19:08,710 --> 00:19:10,140
So, therefore, now if I reload,

375
00:19:10,140 --> 00:19:11,540
here's my image.

376
00:19:11,540 --> 00:19:14,120
Styling is off, no question about that,

377
00:19:14,120 --> 00:19:15,453
but the image is there.

378
00:19:16,410 --> 00:19:19,563
It's being served, and now we can focus on the styling.

