1
00:00:02,050 --> 00:00:04,350
So we can add products

2
00:00:04,350 --> 00:00:07,160
and we can edit products.

3
00:00:07,160 --> 00:00:08,470
In both cases,

4
00:00:08,470 --> 00:00:11,900
we can also choose an image and upload an image.

5
00:00:11,900 --> 00:00:14,060
And that's now the part

6
00:00:14,060 --> 00:00:17,250
where I want to improve the front-end a little bit.

7
00:00:17,250 --> 00:00:20,560
I want to make sure that if we do choose an image here,

8
00:00:20,560 --> 00:00:24,190
we show a little preview next to this image picker

9
00:00:24,190 --> 00:00:27,530
so that we can see which image we actually chose,

10
00:00:27,530 --> 00:00:29,710
and we can visually confirm

11
00:00:29,710 --> 00:00:32,770
that this is the image we want to upload.

12
00:00:32,770 --> 00:00:33,603
Now, of course,

13
00:00:33,603 --> 00:00:36,130
this is also something we did before in the course,

14
00:00:36,130 --> 00:00:39,260
and I will basically apply exactly the same approach

15
00:00:39,260 --> 00:00:41,470
as I did before in the course.

16
00:00:41,470 --> 00:00:44,390
I'll use some front-end JavaScript code,

17
00:00:44,390 --> 00:00:46,880
some browser side Java script code,

18
00:00:46,880 --> 00:00:49,130
to listen for the change event

19
00:00:49,130 --> 00:00:52,570
on this input here, on this file picker,

20
00:00:52,570 --> 00:00:56,180
which will trigger whenever the user does change

21
00:00:56,180 --> 00:00:57,810
the picked file.

22
00:00:57,810 --> 00:01:00,350
And then once that change event fires,

23
00:01:00,350 --> 00:01:02,800
I check if a file has been picked,

24
00:01:02,800 --> 00:01:07,449
and if a file has been picked, I configure a URL,

25
00:01:07,449 --> 00:01:10,230
a preview URL to that file,

26
00:01:10,230 --> 00:01:14,200
which is still locally on the visitor's computer,

27
00:01:14,200 --> 00:01:18,230
but nonetheless, we can create a preview URL to that file,

28
00:01:18,230 --> 00:01:22,030
and then I will add an image or show an image element

29
00:01:22,030 --> 00:01:24,613
that points at that URL, that uses that URL.

30
00:01:27,060 --> 00:01:27,940
That's the plan.

31
00:01:27,940 --> 00:01:30,530
And for this, back in our code,

32
00:01:30,530 --> 00:01:33,060
we got a couple of things to do.

33
00:01:33,060 --> 00:01:36,850
For example, in our product form template,

34
00:01:36,850 --> 00:01:39,080
in our product form EJS file,

35
00:01:39,080 --> 00:01:42,880
We have to make sure that we do have a preview element,

36
00:01:42,880 --> 00:01:44,800
a preview image element,

37
00:01:44,800 --> 00:01:47,750
which we can use to show the image preview.

38
00:01:47,750 --> 00:01:52,470
And I want to show that next to my input here,

39
00:01:52,470 --> 00:01:55,110
and therefore I will actually wrap this paragraph

40
00:01:55,110 --> 00:01:58,060
that holds my label and my file input

41
00:01:58,060 --> 00:02:02,750
with another div, to which I'll add a class,

42
00:02:02,750 --> 00:02:07,750
or an id actually, of image upload control.

43
00:02:09,229 --> 00:02:10,880
Name is up to you of course,

44
00:02:10,880 --> 00:02:13,960
but I'll add that div for styling reasons,

45
00:02:13,960 --> 00:02:16,580
because I want to add an image side by side,

46
00:02:16,580 --> 00:02:18,900
or I want to display an image side by side

47
00:02:18,900 --> 00:02:20,943
to this label input combination.

48
00:02:21,820 --> 00:02:25,320
So I'll move this label input combination in this paragraph

49
00:02:25,320 --> 00:02:26,313
into this div.

50
00:02:27,260 --> 00:02:29,950
And then below that I'll add a image tag,

51
00:02:29,950 --> 00:02:32,890
which has a source and an alt attribute.

52
00:02:32,890 --> 00:02:36,533
And that should now be set with help of JavaScript.

53
00:02:37,710 --> 00:02:42,500
Now the alt text can be selected image, something like this,

54
00:02:42,500 --> 00:02:45,610
but the source, of course, should be set with JavaScript.

55
00:02:45,610 --> 00:02:49,890
And of course it should also not be visible all the time.

56
00:02:49,890 --> 00:02:53,480
Now, before we write the actual JavaScript code, though,

57
00:02:53,480 --> 00:02:56,610
I want to work on the styling here.

58
00:02:56,610 --> 00:02:59,230
I want to make sure that we do position the image

59
00:02:59,230 --> 00:03:02,340
side by side, to the label input combination.

60
00:03:02,340 --> 00:03:05,840
And for this, of course, we need to go to the CSS files.

61
00:03:05,840 --> 00:03:07,840
And now we got a decision to make.

62
00:03:07,840 --> 00:03:11,917
We can add this code for styling this image preview

63
00:03:11,917 --> 00:03:14,600
into the product CSS file,

64
00:03:14,600 --> 00:03:16,880
since we are dealing with products,

65
00:03:16,880 --> 00:03:18,963
the image preview will be for a product.

66
00:03:19,810 --> 00:03:22,840
We could add it to forms CSS since we, of course,

67
00:03:22,840 --> 00:03:24,830
are working in a form.

68
00:03:24,830 --> 00:03:28,560
And ultimately it's up to you, what you prefer.

69
00:03:28,560 --> 00:03:30,630
You could also add a brand new file,

70
00:03:30,630 --> 00:03:33,870
which is a administration specific CSS file,

71
00:03:33,870 --> 00:03:37,713
which you only include on the administration pages.

72
00:03:38,550 --> 00:03:42,220
I will simply go for forms CSS though, and there,

73
00:03:42,220 --> 00:03:46,000
I want to target my image-upload-control by id.

74
00:03:46,000 --> 00:03:50,510
So this div I just added with that image upload control id.

75
00:03:50,510 --> 00:03:53,810
And there, I want to add display flex

76
00:03:53,810 --> 00:03:58,030
so that the paragraph in that div, this paragraph,

77
00:03:58,030 --> 00:04:01,660
and this image, are positioned in the same row.

78
00:04:01,660 --> 00:04:04,623
That's what Flexbox does out of the box, as you know.

79
00:04:06,150 --> 00:04:08,290
And then with the line items center,

80
00:04:08,290 --> 00:04:10,610
we can center those items vertically,

81
00:04:10,610 --> 00:04:14,380
since that's the cross access of the Flexbox row.

82
00:04:14,380 --> 00:04:17,260
And this will then ensure that the items,

83
00:04:17,260 --> 00:04:20,300
the label input combination and the image preview,

84
00:04:20,300 --> 00:04:24,053
are centered on the same horizontal line, so to say.

85
00:04:25,570 --> 00:04:28,870
Now we also of course need more styling though.

86
00:04:28,870 --> 00:04:33,870
I do want to restrict the width of my input

87
00:04:35,060 --> 00:04:37,990
in that image upload control div.

88
00:04:37,990 --> 00:04:39,590
So of that file picker.

89
00:04:39,590 --> 00:04:42,500
it should not take a lot of width

90
00:04:42,500 --> 00:04:45,350
because of course it doesn't need a lot of width.

91
00:04:45,350 --> 00:04:48,130
If you have a look at it, it's not like the other inputs.

92
00:04:48,130 --> 00:04:49,810
And therefore I will actually restrict

93
00:04:49,810 --> 00:04:51,820
the width of this input

94
00:04:51,820 --> 00:04:56,080
in the image upload control div to, let's say, 15 REM

95
00:04:57,270 --> 00:05:00,670
and set this as a max width maybe.

96
00:05:00,670 --> 00:05:03,760
And then of course you also want to style the image.

97
00:05:03,760 --> 00:05:07,380
So inside of this image upload control div,

98
00:05:07,380 --> 00:05:10,200
I want to target the image element,

99
00:05:10,200 --> 00:05:14,340
and there make sure that we got the proper styling as well.

100
00:05:14,340 --> 00:05:17,550
That means that I do want to give that,

101
00:05:17,550 --> 00:05:21,980
let's say a width of 4 Rem and a height of 4 Rem.

102
00:05:21,980 --> 00:05:25,960
So width 4 Rem, height 4 Rem,

103
00:05:25,960 --> 00:05:27,780
and you can play around with these numbers

104
00:05:27,780 --> 00:05:30,320
to find a good width and height.

105
00:05:30,320 --> 00:05:33,050
And I want to set object fit to cover

106
00:05:33,050 --> 00:05:37,000
to make sure that this is not distorted,

107
00:05:37,000 --> 00:05:38,373
but instead cropped.

108
00:05:39,240 --> 00:05:43,370
And I'll give it a border radius of border radius small

109
00:05:43,370 --> 00:05:45,563
so that we have some rounded corners.

110
00:05:46,720 --> 00:05:50,160
Now with that, if you save everything and reload,

111
00:05:50,160 --> 00:05:51,500
we got this image here,

112
00:05:51,500 --> 00:05:53,700
and of course we got no image at the moment,

113
00:05:53,700 --> 00:05:56,733
but we can see where the image will appear later.

114
00:05:58,230 --> 00:06:00,360
Now, by default at the beginning,

115
00:06:00,360 --> 00:06:02,550
it should not be visible though.

116
00:06:02,550 --> 00:06:05,740
I only want to display this image once we get a image

117
00:06:05,740 --> 00:06:08,490
and therefore I'll set display to none here

118
00:06:08,490 --> 00:06:10,110
on that selected image.

119
00:06:10,110 --> 00:06:12,760
So that from the start, it's not there,

120
00:06:12,760 --> 00:06:15,003
it will only appear once we chose an image.

121
00:06:16,350 --> 00:06:20,210
So that's now the image preview element and the styling.

122
00:06:20,210 --> 00:06:23,133
Now we need the JavaScript code to add the logic.

123
00:06:24,260 --> 00:06:25,750
Now for this, of course,

124
00:06:25,750 --> 00:06:28,640
we need to go to the scripts folder in the public folder

125
00:06:28,640 --> 00:06:31,980
and add a brand new scripts file.

126
00:06:31,980 --> 00:06:34,090
I'll name it, image-preview.js

127
00:06:34,090 --> 00:06:37,463
since that's what this file will help us with.

128
00:06:38,330 --> 00:06:40,980
And in this file, I, first of all,

129
00:06:40,980 --> 00:06:43,990
need to get access to this input element

130
00:06:43,990 --> 00:06:46,600
so that we can add an event listener to it.

131
00:06:46,600 --> 00:06:48,810
And then to this image preview element,

132
00:06:48,810 --> 00:06:50,990
which is currently not shown on the screen,

133
00:06:50,990 --> 00:06:54,040
so that we can set the source of that element

134
00:06:54,040 --> 00:06:56,900
and show it once we get a image.

135
00:06:56,900 --> 00:07:01,900
So I need the image picker element, you could say,

136
00:07:02,880 --> 00:07:06,620
and we get that with document, and then let's see,

137
00:07:06,620 --> 00:07:09,770
how can we select this file input?

138
00:07:09,770 --> 00:07:12,500
There are various ways of doing that.

139
00:07:12,500 --> 00:07:14,640
I would say we can, for example,

140
00:07:14,640 --> 00:07:18,120
select the input that we find in an element

141
00:07:18,120 --> 00:07:21,420
with the id of image upload control.

142
00:07:21,420 --> 00:07:24,860
Alternatively, we could simply select it by id here

143
00:07:24,860 --> 00:07:27,960
or in a lot of other ways as well.

144
00:07:27,960 --> 00:07:30,920
To practice different ways of selecting elements,

145
00:07:30,920 --> 00:07:32,860
I will go for the query selector,

146
00:07:32,860 --> 00:07:35,930
which we haven't used thus far in this section,

147
00:07:35,930 --> 00:07:40,090
and I'll start by selecting the image upload control div,

148
00:07:40,090 --> 00:07:42,450
so the element with that id.

149
00:07:42,450 --> 00:07:46,550
And this is the id CSS selector, so we use that here

150
00:07:46,550 --> 00:07:51,550
because querySelector wants CSS selectors in its argument.

151
00:07:51,930 --> 00:07:54,790
And then I'm interested in the first input.

152
00:07:54,790 --> 00:07:58,280
And hence, we can write this CSS selector

153
00:07:58,280 --> 00:08:00,930
to select this input in the div

154
00:08:00,930 --> 00:08:03,533
with this id with help of querySelector.

155
00:08:05,630 --> 00:08:07,890
Now, I don't just need the image picker element.

156
00:08:07,890 --> 00:08:11,500
I also need the image preview element, which is the image.

157
00:08:11,500 --> 00:08:13,590
And of course we can use a similar approach

158
00:08:13,590 --> 00:08:14,740
and just copy that.

159
00:08:14,740 --> 00:08:17,203
And instead of the input, select the image.

160
00:08:18,110 --> 00:08:20,910
Again, alternatives would have been to use the id

161
00:08:20,910 --> 00:08:23,620
or any other kind of CSS selector,

162
00:08:23,620 --> 00:08:25,703
but this should also do the trick.

163
00:08:27,220 --> 00:08:30,070
Now we need to add a function that should be triggered

164
00:08:30,070 --> 00:08:33,210
once the image picker fires the change event.

165
00:08:33,210 --> 00:08:35,690
So once the user changes the picked image.

166
00:08:35,690 --> 00:08:38,159
And I'll name this update image preview.

167
00:08:38,159 --> 00:08:41,130
That sounds like a fitting name for this function,

168
00:08:41,130 --> 00:08:42,903
which describes what it will do.

169
00:08:44,560 --> 00:08:47,020
So we'll add logic to this function in a second.

170
00:08:47,020 --> 00:08:49,700
For the moment I'll just wire it up to the change event

171
00:08:49,700 --> 00:08:51,570
on the image picker element.

172
00:08:51,570 --> 00:08:53,930
So we use that image picker element

173
00:08:53,930 --> 00:08:56,470
and call add event listener.

174
00:08:56,470 --> 00:08:58,540
And the event I do want to listen to

175
00:08:58,540 --> 00:09:01,560
is the change event here,

176
00:09:01,560 --> 00:09:04,100
which will trigger whenever the user changes

177
00:09:04,100 --> 00:09:05,700
to pick the image.

178
00:09:05,700 --> 00:09:08,590
And then as a second parameter value, here,

179
00:09:08,590 --> 00:09:11,510
we point at the update image preview function,

180
00:09:11,510 --> 00:09:14,653
which should be executed once a image was picked.

181
00:09:16,220 --> 00:09:19,570
Now in that function, we can now extract an array

182
00:09:19,570 --> 00:09:23,310
of all the files that have been picked, since theoretically,

183
00:09:23,310 --> 00:09:25,430
you could configure the input elements

184
00:09:25,430 --> 00:09:28,100
such that you can select multiple images,

185
00:09:28,100 --> 00:09:31,890
though that's not what we support in this website here,

186
00:09:31,890 --> 00:09:33,010
but we can get a list

187
00:09:33,010 --> 00:09:35,880
of all the files that have been selected

188
00:09:35,880 --> 00:09:38,230
by reaching out to the image picker element,

189
00:09:38,230 --> 00:09:41,240
so this file picker input element,

190
00:09:41,240 --> 00:09:44,343
and accessing the files property there.

191
00:09:45,270 --> 00:09:47,320
Now this is an array, but in our case,

192
00:09:47,320 --> 00:09:50,163
it will always be an array with exactly one element.

193
00:09:51,220 --> 00:09:53,990
Nonetheless, I want to check if no files have been picked,

194
00:09:53,990 --> 00:09:57,600
so if files is maybe not truthy, if it's falsey,

195
00:09:57,600 --> 00:10:00,520
or if file's length is equal to zero,

196
00:10:00,520 --> 00:10:02,990
which means no image has been picked.

197
00:10:02,990 --> 00:10:06,460
This could be the case if previously a file was picked

198
00:10:06,460 --> 00:10:08,670
and the user now deselected that.

199
00:10:09,720 --> 00:10:11,990
In that case, if no file was picked,

200
00:10:11,990 --> 00:10:14,190
I want to return and not continue

201
00:10:14,190 --> 00:10:17,980
with any logic I'm about to add after this if check.

202
00:10:17,980 --> 00:10:18,813
But in addition,

203
00:10:18,813 --> 00:10:21,730
I also want to reach out to my image preview element,

204
00:10:21,730 --> 00:10:23,680
so to this image element,

205
00:10:23,680 --> 00:10:26,430
and access the style property there

206
00:10:26,430 --> 00:10:30,000
and set the display style to none, to hide it again,

207
00:10:30,000 --> 00:10:32,173
in case it was shown in the meantime.

208
00:10:33,760 --> 00:10:35,500
If you make it past this if check,

209
00:10:35,500 --> 00:10:38,420
we know that we got files, and in that case,

210
00:10:38,420 --> 00:10:43,340
my picked file is actually the first and only file

211
00:10:43,340 --> 00:10:45,160
in that array of files,

212
00:10:45,160 --> 00:10:49,150
since in this website, we only support picking one file.

213
00:10:49,150 --> 00:10:52,290
And then we want to construct a URL to that file.

214
00:10:52,290 --> 00:10:54,580
Now, important, as mentioned before,

215
00:10:54,580 --> 00:10:58,140
this file lives on the computer of our visitor,

216
00:10:58,140 --> 00:10:59,900
not on our server.

217
00:10:59,900 --> 00:11:04,380
Still, JavaScript, browser side JavaScript to be precise,

218
00:11:04,380 --> 00:11:08,690
gives us ways of constructing URLs to local files

219
00:11:08,690 --> 00:11:12,140
that have been provided by the visitor of our site

220
00:11:12,140 --> 00:11:15,503
as the visitor did it here with the image picker.

221
00:11:16,430 --> 00:11:20,993
We can create such a URL with the built-in URL class,

222
00:11:22,180 --> 00:11:25,713
so that's a class built into front-end JavaScript.

223
00:11:26,670 --> 00:11:27,660
And on that class,

224
00:11:27,660 --> 00:11:32,290
we've got a static method called create object URL.

225
00:11:32,290 --> 00:11:35,620
Since it's static, we don't have to instantiate the class.

226
00:11:35,620 --> 00:11:39,020
We can just call this static method on the class,

227
00:11:39,020 --> 00:11:41,130
as we did it with our own model classes

228
00:11:41,130 --> 00:11:44,340
on the backend as well in the last lectures.

229
00:11:44,340 --> 00:11:48,683
And to create object URL, we pass the picked file.

230
00:11:49,530 --> 00:11:53,100
This will generate a URL that will work on the computer

231
00:11:53,100 --> 00:11:55,893
of our visitor who picked that file.

232
00:11:57,500 --> 00:12:00,620
Now this is the URL I want to set as a source

233
00:12:00,620 --> 00:12:02,750
on the image preview element.

234
00:12:02,750 --> 00:12:07,200
So there we can access the SRC property to set that source

235
00:12:07,200 --> 00:12:10,283
and set it equal to that generated URL.

236
00:12:11,180 --> 00:12:12,910
And then of course, I also want to make sure

237
00:12:12,910 --> 00:12:15,330
that this preview element is visible.

238
00:12:15,330 --> 00:12:18,070
So I will access the display style here

239
00:12:18,070 --> 00:12:21,580
and show this element by setting the display style

240
00:12:21,580 --> 00:12:23,733
of that image to block.

241
00:12:25,980 --> 00:12:28,290
Alternatively, you could also set it to inline.

242
00:12:28,290 --> 00:12:29,460
That doesn't matter.

243
00:12:29,460 --> 00:12:30,800
The only thing that does matter

244
00:12:30,800 --> 00:12:33,733
is that it's not set to none.

245
00:12:35,260 --> 00:12:38,430
Now we need to make sure that this image-preview.js file

246
00:12:38,430 --> 00:12:43,430
becomes active when we are on one of our form sites,

247
00:12:43,450 --> 00:12:47,770
so if we are on the new product or update product sites,

248
00:12:47,770 --> 00:12:51,600
and therefore we should go to new product EJS,

249
00:12:51,600 --> 00:12:55,130
and there, before we close the head section,

250
00:12:55,130 --> 00:12:57,970
add a script import, as we learned it,

251
00:12:57,970 --> 00:12:59,660
by pointing at scripts

252
00:12:59,660 --> 00:13:03,410
and then image dash preview js was the name,

253
00:13:03,410 --> 00:13:06,410
and add defer to make sure it only executes

254
00:13:06,410 --> 00:13:09,743
after all the HTML content here has been parsed.

255
00:13:10,720 --> 00:13:13,660
And do the same for the update product EJS file

256
00:13:13,660 --> 00:13:16,453
so that there, we also see a image preview.

257
00:13:19,140 --> 00:13:20,400
Now with all that done,

258
00:13:20,400 --> 00:13:23,890
if we save that and I reload the new product page,

259
00:13:23,890 --> 00:13:28,890
if I choose a file here, let's say I'm adding a track pad,

260
00:13:29,010 --> 00:13:30,453
I see a preview here.

261
00:13:31,300 --> 00:13:33,913
So now I can add this product as well,

262
00:13:34,750 --> 00:13:37,253
our great mouse alternative.

263
00:13:40,540 --> 00:13:45,540
It helps you navigate around on your system

264
00:13:47,690 --> 00:13:50,220
and it's all white.

265
00:13:50,220 --> 00:13:51,400
Yeah.

266
00:13:51,400 --> 00:13:53,380
So now we can add this product as well.

267
00:13:53,380 --> 00:13:54,213
Click save.

268
00:13:54,213 --> 00:13:56,400
And now we've got the magic track pad here,

269
00:13:56,400 --> 00:14:00,500
the keyboard here, and yeah, these are super fancy products.

270
00:14:00,500 --> 00:14:01,460
It's all the same.

271
00:14:01,460 --> 00:14:04,710
Sorry, I just took photos of what I have in front of me,

272
00:14:04,710 --> 00:14:06,780
but now we have these products here

273
00:14:06,780 --> 00:14:09,410
and now let's also see if the preview works

274
00:14:09,410 --> 00:14:11,370
if we are editing.

275
00:14:11,370 --> 00:14:15,357
For this I'll pick the keyboard here, and that works.

276
00:14:15,357 --> 00:14:16,720
And if I would save this,

277
00:14:16,720 --> 00:14:19,590
you see it was also uploaded and replaced.

278
00:14:19,590 --> 00:14:21,360
Also if I reload this page.

279
00:14:21,360 --> 00:14:24,100
But of course here I want to go back to the track pad

280
00:14:24,100 --> 00:14:26,350
Preview works, saving works.

281
00:14:26,350 --> 00:14:28,180
This all looks good.

282
00:14:28,180 --> 00:14:30,580
And that's how we can add such an image preview.

