1
00:00:01,753 --> 00:00:03,730
So let's move to the frontend

2
00:00:03,730 --> 00:00:07,720
and make sure that we send such a JavaScript-driven request,

3
00:00:07,720 --> 00:00:09,540
such a AJAX request,

4
00:00:09,540 --> 00:00:12,020
to this route from the frontend.

5
00:00:12,020 --> 00:00:12,880
And for this, of course,

6
00:00:12,880 --> 00:00:16,430
it's again time for frontend JavaScript.

7
00:00:16,430 --> 00:00:19,710
I'll add a new file in the public scripts folder for that,

8
00:00:19,710 --> 00:00:24,160
and I'll name it product-management.js.

9
00:00:24,160 --> 00:00:25,670
Filename, of course, is up to you,

10
00:00:25,670 --> 00:00:28,300
but it will help us with managing products.

11
00:00:28,300 --> 00:00:31,093
It will help us with deleting products specifically.

12
00:00:32,549 --> 00:00:35,550
Now, in this product-management.js file,

13
00:00:35,550 --> 00:00:38,610
I wanna listen to clicks on the Delete buttons.

14
00:00:38,610 --> 00:00:41,300
And, of course, we have multiple Delete buttons

15
00:00:41,300 --> 00:00:43,140
if we have multiple products.

16
00:00:43,140 --> 00:00:45,950
I wanna listen to clicks on all of them.

17
00:00:45,950 --> 00:00:47,530
And then, of course, I need to find out

18
00:00:47,530 --> 00:00:50,430
which Delete button for which product was clicked

19
00:00:50,430 --> 00:00:52,600
so that we send the correct request

20
00:00:52,600 --> 00:00:55,410
with the correct ID to the backend.

21
00:00:55,410 --> 00:00:57,750
And then once we did all of that,

22
00:00:57,750 --> 00:01:00,670
we, of course, do want to send that request

23
00:01:00,670 --> 00:01:02,850
with that ID of the clicked item

24
00:01:02,850 --> 00:01:05,640
so that this delete is initiated.

25
00:01:05,640 --> 00:01:07,730
And then once that delete succeeded

26
00:01:07,730 --> 00:01:09,360
and we got back a response,

27
00:01:09,360 --> 00:01:13,400
I wanna update the DOM with browser-side JavaScript

28
00:01:13,400 --> 00:01:15,910
to manually remove the product item

29
00:01:15,910 --> 00:01:18,373
for which the Delete button was clicked.

30
00:01:19,400 --> 00:01:21,190
So plenty of things to do.

31
00:01:21,190 --> 00:01:23,160
Let's start by adding event listeners

32
00:01:23,160 --> 00:01:24,800
to all these Delete buttons.

33
00:01:24,800 --> 00:01:26,690
And for that, of course, we need to get access

34
00:01:26,690 --> 00:01:28,023
to those Delete buttons.

35
00:01:29,140 --> 00:01:30,350
Now, for that,

36
00:01:30,350 --> 00:01:34,450
if we have a look at the product-item.ejs file,

37
00:01:34,450 --> 00:01:36,250
we can see that all these buttons

38
00:01:36,250 --> 00:01:38,100
have, of course, btn classes,

39
00:01:38,100 --> 00:01:40,620
and I don't wanna select by that.

40
00:01:40,620 --> 00:01:44,020
I would also select wrong things if I did that.

41
00:01:44,020 --> 00:01:47,500
Instead, I will select with help of that product-item class,

42
00:01:47,500 --> 00:01:49,060
which I have on this article,

43
00:01:49,060 --> 00:01:51,790
and then select the first and in this case only button

44
00:01:51,790 --> 00:01:54,053
that I have inside of these product-items.

45
00:01:55,710 --> 00:01:59,130
So in the product-management.js file,

46
00:01:59,130 --> 00:02:01,520
this frontend JavaScript file,

47
00:02:01,520 --> 00:02:06,520
I will get my deletion or my deleteProductButtonElements

48
00:02:08,199 --> 00:02:09,993
by using document.querySelectorAll,

49
00:02:12,398 --> 00:02:13,400
and that's important.

50
00:02:13,400 --> 00:02:16,590
We need querySelectorAll here since that will then give us

51
00:02:16,590 --> 00:02:18,950
an array of all matched elements

52
00:02:18,950 --> 00:02:22,130
instead of just the first matching element.

53
00:02:22,130 --> 00:02:25,430
And I will select all the buttons

54
00:02:25,430 --> 00:02:28,930
inside of elements that have the product-item class,

55
00:02:28,930 --> 00:02:32,093
and this is the appropriate CSS selector for that.

56
00:02:34,290 --> 00:02:38,540
So with that, we got all these button elements.

57
00:02:38,540 --> 00:02:40,560
And now, of course, I wanna add event listeners

58
00:02:40,560 --> 00:02:41,550
to all of them.

59
00:02:41,550 --> 00:02:42,720
And to achieve this,

60
00:02:42,720 --> 00:02:46,330
we can loop through them, for example, with a for-of loop

61
00:02:46,330 --> 00:02:49,160
to get the deleteProductButtonElement

62
00:02:51,550 --> 00:02:55,400
whilst looping through the deleteProductButtonElements.

63
00:02:55,400 --> 00:02:57,350
And yes, these are long names,

64
00:02:57,350 --> 00:03:00,100
but I wanna use explicit, clear names here

65
00:03:00,100 --> 00:03:03,610
so that it's obvious what's stored inside of them.

66
00:03:03,610 --> 00:03:06,960
And then for the single elements here,

67
00:03:06,960 --> 00:03:11,333
I want to add event listeners and listen to click events.

68
00:03:12,490 --> 00:03:15,610
And then, of course, I want to trigger a function

69
00:03:15,610 --> 00:03:18,090
when such a button is clicked,

70
00:03:18,090 --> 00:03:20,240
a function that should actually have a name,

71
00:03:20,240 --> 00:03:22,677
and the name could be deleteProduct

72
00:03:22,677 --> 00:03:24,960
because that's what we'll do.

73
00:03:24,960 --> 00:03:29,453
So here we wanna point at deleteProduct at this function.

74
00:03:31,260 --> 00:03:33,080
Now we got the click listener.

75
00:03:33,080 --> 00:03:35,510
Of course, now we need a way of finding out

76
00:03:35,510 --> 00:03:39,110
for which product the Delete button was clicked.

77
00:03:39,110 --> 00:03:41,950
And there will be various ways of doing that.

78
00:03:41,950 --> 00:03:45,190
One great way, which I also showed you before in the course,

79
00:03:45,190 --> 00:03:47,803
is to utilize data attributes.

80
00:03:48,640 --> 00:03:52,950
We can add the special data dash attribute to our elements.

81
00:03:52,950 --> 00:03:54,690
And when we do so,

82
00:03:54,690 --> 00:03:59,690
we can add arbitrary data pieces, simple data pieces,

83
00:04:00,120 --> 00:04:01,750
to our elements.

84
00:04:01,750 --> 00:04:02,860
For example, here we could add

85
00:04:02,860 --> 00:04:06,620
a product id data piece to this button

86
00:04:06,620 --> 00:04:07,763
with data-productid.

87
00:04:09,020 --> 00:04:12,010
The part after the dash is up to you.

88
00:04:12,010 --> 00:04:16,480
And then here, use EJS to inject the concrete value

89
00:04:16,480 --> 00:04:19,829
which will be different for every product item.

90
00:04:19,829 --> 00:04:21,993
And, of course, it should be product.id.

91
00:04:23,470 --> 00:04:27,780
Now, inside of this deleteProduct function here,

92
00:04:27,780 --> 00:04:32,460
we can get access to that by accessing the dataset property

93
00:04:32,460 --> 00:04:34,783
of the button for which this event occurred.

94
00:04:35,890 --> 00:04:38,140
Now, the only remaining problem here, of course,

95
00:04:38,140 --> 00:04:40,440
is that we got multiple buttons.

96
00:04:40,440 --> 00:04:42,290
How do we know which button was clicked

97
00:04:42,290 --> 00:04:44,697
inside of deleteProduct?

98
00:04:44,697 --> 00:04:47,770
For this, we can utilize the default event object

99
00:04:47,770 --> 00:04:48,763
which we get here.

100
00:04:49,810 --> 00:04:54,810
You might remember that we have these event parameter values

101
00:04:55,030 --> 00:04:56,690
which we get automatically

102
00:04:56,690 --> 00:05:00,100
for all the functions that are triggered upon events

103
00:05:00,100 --> 00:05:02,150
so that we use with event listener,

104
00:05:02,150 --> 00:05:03,643
addEventListener in the end.

105
00:05:04,670 --> 00:05:07,320
We get a event object that describes the event

106
00:05:07,320 --> 00:05:10,140
that occurred automatically by the browser.

107
00:05:10,140 --> 00:05:14,120
And on this event object, we have a target property.

108
00:05:14,120 --> 00:05:17,410
This target is the element which caused the event

109
00:05:17,410 --> 00:05:19,770
or on which the event occurred.

110
00:05:19,770 --> 00:05:23,090
And in our case, we know that this will be the button,

111
00:05:23,090 --> 00:05:26,880
the buttonElement on which the user clicked,

112
00:05:26,880 --> 00:05:29,360
so the concrete button for a concrete product

113
00:05:29,360 --> 00:05:31,180
on which the user clicked.

114
00:05:31,180 --> 00:05:34,270
And then the productId, of course, can be extracted

115
00:05:34,270 --> 00:05:39,200
by using this buttonElement and there the dataset property

116
00:05:39,200 --> 00:05:40,830
because that's how we get access

117
00:05:40,830 --> 00:05:44,410
to these data dash attribute values.

118
00:05:44,410 --> 00:05:47,760
You get access with help of the dataset property.

119
00:05:47,760 --> 00:05:49,890
And on the dataset property,

120
00:05:49,890 --> 00:05:53,500
the parts after the dash will be properties.

121
00:05:53,500 --> 00:05:56,390
So in this case I'll have a productid property

122
00:05:56,390 --> 00:05:59,810
written like this on this dataset object

123
00:05:59,810 --> 00:06:02,290
which it turns out to be for the button

124
00:06:02,290 --> 00:06:04,360
on which the click occurred.

125
00:06:04,360 --> 00:06:06,460
And that is then the product ID

126
00:06:06,460 --> 00:06:08,570
which I wanna send to my backend

127
00:06:08,570 --> 00:06:11,260
when I send this AJAX request.

128
00:06:11,260 --> 00:06:14,970
And speaking of that, that's the next thing I wanna do.

129
00:06:14,970 --> 00:06:17,660
I wanna send this request to the backend.

130
00:06:17,660 --> 00:06:21,010
And before doing that, we got various options.

131
00:06:21,010 --> 00:06:25,160
We can use third-party packages like the axios package,

132
00:06:25,160 --> 00:06:29,210
which is a super popular package for sending HTTP requests

133
00:06:29,210 --> 00:06:31,940
from inside your JavaScript code.

134
00:06:31,940 --> 00:06:34,920
It's great, and if you use that, that's absolutely fine.

135
00:06:34,920 --> 00:06:36,420
There's nothing wrong with it.

136
00:06:37,410 --> 00:06:40,360
Here, however, I will use

137
00:06:40,360 --> 00:06:42,620
an approach that's built into the browser.

138
00:06:42,620 --> 00:06:44,910
I'll use the fetch function,

139
00:06:44,910 --> 00:06:48,530
which is available out of the box in browsers.

140
00:06:48,530 --> 00:06:50,950
The fetch function sounds like it's only used

141
00:06:50,950 --> 00:06:53,300
for fetching data, for getting data,

142
00:06:53,300 --> 00:06:56,430
but actually we can also use it for sending POST

143
00:06:56,430 --> 00:06:59,533
or, in our case, also DELETE requests.

144
00:07:00,690 --> 00:07:02,780
Now, fetch, first of all, wants a URL

145
00:07:02,780 --> 00:07:05,710
to which the request should be sent.

146
00:07:05,710 --> 00:07:07,060
And in our case,

147
00:07:07,060 --> 00:07:09,570
that should be the domain on which we already are,

148
00:07:09,570 --> 00:07:11,910
so we don't need to repeat that here,

149
00:07:11,910 --> 00:07:16,360
slash and then the path on that domain

150
00:07:16,360 --> 00:07:18,253
where we wanna send the request to.

151
00:07:19,110 --> 00:07:24,110
In our case, that would be /admin/products and then the id.

152
00:07:24,430 --> 00:07:28,637
So here I'll then concatenate the productId.

153
00:07:29,900 --> 00:07:33,100
You could also repeat your domain name, by the way.

154
00:07:33,100 --> 00:07:34,890
And you would need to do that

155
00:07:34,890 --> 00:07:37,290
if you send a request to a server

156
00:07:37,290 --> 00:07:40,690
that's not the server that's hosting this website.

157
00:07:40,690 --> 00:07:42,910
If you're sending the request to a different server

158
00:07:42,910 --> 00:07:44,230
with a different domain,

159
00:07:44,230 --> 00:07:46,600
you need to include the domain here.

160
00:07:46,600 --> 00:07:47,860
If you're sending a request

161
00:07:47,860 --> 00:07:50,550
to the very server that served this page, though,

162
00:07:50,550 --> 00:07:52,550
then you don't need to repeat the domain.

163
00:07:52,550 --> 00:07:56,150
You just need an absolute path that starts with slash,

164
00:07:56,150 --> 00:07:58,510
and then it will automatically be appended

165
00:07:58,510 --> 00:08:00,773
to the domain on which you currently are.

166
00:08:02,100 --> 00:08:03,550
So this will send a request

167
00:08:03,550 --> 00:08:07,410
to /admin/products/ the id of that product,

168
00:08:07,410 --> 00:08:10,260
but now we also need to configure this request,

169
00:08:10,260 --> 00:08:13,300
which we do by passing a second-parameter value

170
00:08:13,300 --> 00:08:14,680
to the fetch function

171
00:08:14,680 --> 00:08:17,180
which is an object full of key-value pairs

172
00:08:17,180 --> 00:08:19,800
that we can use for configuring.

173
00:08:19,800 --> 00:08:21,440
And we need to configure here

174
00:08:21,440 --> 00:08:24,340
because by default we would send a GET request,

175
00:08:24,340 --> 00:08:26,700
and that's not what I wanna do here.

176
00:08:26,700 --> 00:08:29,610
I wanna send a DELETE request instead.

177
00:08:29,610 --> 00:08:32,419
Now, we can change the method, the HTTP method,

178
00:08:32,419 --> 00:08:34,400
that's being sent or that's being used

179
00:08:34,400 --> 00:08:38,419
by setting the method property on this configuration object.

180
00:08:38,419 --> 00:08:41,990
And the default is GET, we could set it to POST,

181
00:08:41,990 --> 00:08:44,310
but here we'll set it to DELETE.

182
00:08:44,310 --> 00:08:49,310
And that's the first time we use such a special HTTP method

183
00:08:49,340 --> 00:08:51,180
which actually isn't that special.

184
00:08:51,180 --> 00:08:54,140
The only special thing is that we can't send it

185
00:08:54,140 --> 00:08:56,790
when we just work with links and forms

186
00:08:56,790 --> 00:08:59,160
without any frontend JavaScript,

187
00:08:59,160 --> 00:09:02,770
but that, instead, we need JavaScript to send requests

188
00:09:02,770 --> 00:09:04,970
that have this kind of method.

189
00:09:04,970 --> 00:09:08,310
But then it's absolutely normal to use this feature.

190
00:09:08,310 --> 00:09:11,800
And here, sending a DELETE request simply makes more sense

191
00:09:11,800 --> 00:09:14,230
than sending a POST request with the form,

192
00:09:14,230 --> 00:09:16,140
though we could also do that.

193
00:09:16,140 --> 00:09:19,070
That would not be bad. It wouldn't cause problems.

194
00:09:19,070 --> 00:09:20,750
But if we have the opportunity

195
00:09:20,750 --> 00:09:23,930
of sending a more specific DELETE request instead,

196
00:09:23,930 --> 00:09:25,403
we might simply do that.

197
00:09:26,570 --> 00:09:30,430
Now, there is one thing we should also do for this request,

198
00:09:30,430 --> 00:09:33,063
and that involves our CSRF token.

199
00:09:34,020 --> 00:09:37,950
We need to send the CSRF token with that request as well

200
00:09:37,950 --> 00:09:41,870
because otherwise the request will be blocked by our server,

201
00:09:41,870 --> 00:09:45,130
because the CSRF protection we added on the server

202
00:09:45,130 --> 00:09:49,690
also affects the request we send with frontend JavaScript,

203
00:09:49,690 --> 00:09:52,020
not just requests that are sent

204
00:09:52,020 --> 00:09:54,110
because some form is submitted.

205
00:09:54,110 --> 00:09:55,430
And that's a good thing.

206
00:09:55,430 --> 00:09:58,250
We want that protection against all requests

207
00:09:58,250 --> 00:09:59,703
no matter how they are sent.

208
00:10:01,230 --> 00:10:03,620
Now, to send the CSRF token along,

209
00:10:03,620 --> 00:10:06,160
we could add it in the request body.

210
00:10:06,160 --> 00:10:08,670
But it turns out that for DELETE requests,

211
00:10:08,670 --> 00:10:11,410
you typically don't have a request body.

212
00:10:11,410 --> 00:10:15,350
Instead, we simply add the CSRF token in the URL

213
00:10:15,350 --> 00:10:17,210
as a query parameter

214
00:10:17,210 --> 00:10:20,860
by adding the _csrf query parameter.

215
00:10:20,860 --> 00:10:23,720
You add query parameters by adding a question mark

216
00:10:23,720 --> 00:10:26,520
and then your key-value pairs.

217
00:10:26,520 --> 00:10:30,060
And then we need to get access to that CSRF token

218
00:10:30,060 --> 00:10:31,993
to add it into this URL.

219
00:10:32,842 --> 00:10:34,470
Now, we can get access

220
00:10:34,470 --> 00:10:37,330
just as we get access to the productid.

221
00:10:37,330 --> 00:10:40,283
Back in the template, besides adding data-productid,

222
00:10:41,500 --> 00:10:46,500
we could add data-csrf to also use EJS here

223
00:10:46,540 --> 00:10:49,500
to access locals.csrfToken

224
00:10:49,500 --> 00:10:53,110
and add that CSRF token that we need on the data

225
00:10:53,110 --> 00:10:54,910
or with a data attribute

226
00:10:54,910 --> 00:10:56,583
to this Delete button as well.

227
00:10:58,890 --> 00:11:01,780
And once we did that, in product-management,

228
00:11:01,780 --> 00:11:05,110
we can, of course, get our csrfToken here

229
00:11:05,110 --> 00:11:10,110
by accessing buttonElement.dataset.csrf, oops, csrf

230
00:11:12,270 --> 00:11:16,813
because I chose csrf as an identifier after data dash.

231
00:11:18,530 --> 00:11:22,760
So now we can add that csrfToken here,

232
00:11:22,760 --> 00:11:25,373
and that should then send a valid request.

233
00:11:26,810 --> 00:11:29,140
Now, that's actually all we need to configure here

234
00:11:29,140 --> 00:11:32,980
since we're not adding any body, any request body,

235
00:11:32,980 --> 00:11:34,170
to that request.

236
00:11:34,170 --> 00:11:38,230
We also don't need to set any special headers or metadata,

237
00:11:38,230 --> 00:11:41,303
and hence sending the fetch request like this is enough.

238
00:11:43,050 --> 00:11:47,010
Now we, of course, wanna wait until we have a response

239
00:11:47,010 --> 00:11:49,410
and then update what we see on the screen.

240
00:11:49,410 --> 00:11:52,600
We wanna remove the item on the screen which was deleted

241
00:11:52,600 --> 00:11:54,550
without reloading the screen,

242
00:11:54,550 --> 00:11:56,350
which we could, of course, also do.

243
00:11:56,350 --> 00:11:57,970
But I want to update the DOM

244
00:11:57,970 --> 00:12:00,420
from inside frontend JavaScript code

245
00:12:00,420 --> 00:12:03,473
to delete the item manually with JavaScript.

246
00:12:04,560 --> 00:12:06,280
Now, fetch returns a promise,

247
00:12:06,280 --> 00:12:09,150
so I wanna wait until I got that response,

248
00:12:09,150 --> 00:12:12,700
so once that promise yielded that response,

249
00:12:12,700 --> 00:12:16,280
and hence we can use async await here as well.

250
00:12:16,280 --> 00:12:18,330
That works in the browser as well,

251
00:12:18,330 --> 00:12:23,040
so we can run async await here and await the result of this

252
00:12:23,040 --> 00:12:27,610
which is the response like this.

253
00:12:27,610 --> 00:12:30,090
And then we can check if the response is okay

254
00:12:30,090 --> 00:12:32,210
or if we got back an error

255
00:12:32,210 --> 00:12:35,580
by checking if not response okay,

256
00:12:35,580 --> 00:12:38,420
so if we don't have an okay response,

257
00:12:38,420 --> 00:12:42,180
if the status code of the response is not 200

258
00:12:42,180 --> 00:12:45,440
or any other 200-ish number,

259
00:12:45,440 --> 00:12:49,610
in that case, I wanna show an error message to the user,

260
00:12:49,610 --> 00:12:53,360
and I'll use the built-in alert for that and just say

261
00:12:54,500 --> 00:12:57,140
Something went wrong.

262
00:12:57,140 --> 00:13:00,270
Of course, you could alternatively also write code here

263
00:13:00,270 --> 00:13:03,520
that shows the error message right in the DOM

264
00:13:03,520 --> 00:13:06,730
so that you add a modal or some error box

265
00:13:06,730 --> 00:13:07,863
or anything like that.

266
00:13:08,940 --> 00:13:10,560
I'll go for this alert,

267
00:13:10,560 --> 00:13:14,690
and then return so that no other code executes thereafter,

268
00:13:14,690 --> 00:13:16,797
then we can move on.

269
00:13:16,797 --> 00:13:19,630
Now we know that the response was okay,

270
00:13:19,630 --> 00:13:22,620
and that's now when I wanna update the DOM.

271
00:13:22,620 --> 00:13:23,770
And for this, of course,

272
00:13:23,770 --> 00:13:26,580
I again wanna remove this product-item

273
00:13:26,580 --> 00:13:28,580
for which the Delete button was clicked.

274
00:13:29,700 --> 00:13:32,720
Now, the good thing is we know which button was clicked.

275
00:13:32,720 --> 00:13:36,190
We got access to that inside of deleteProduct.

276
00:13:36,190 --> 00:13:39,910
So if we now wanna find the product item that belongs to it,

277
00:13:39,910 --> 00:13:44,100
we could, for example, do some DOM traversal

278
00:13:44,100 --> 00:13:45,993
to move up to this article.

279
00:13:46,880 --> 00:13:50,120
The button is inside that div, which is inside that div,

280
00:13:50,120 --> 00:13:51,653
which is inside that article.

281
00:13:52,500 --> 00:13:54,960
So we could say from the button's perspective,

282
00:13:54,960 --> 00:13:57,720
since we got access to the button in our function,

283
00:13:57,720 --> 00:13:59,810
we can access the parent element,

284
00:13:59,810 --> 00:14:03,240
and then the parent of that, and then the parent of that,

285
00:14:03,240 --> 00:14:05,040
and that would be the product item

286
00:14:05,040 --> 00:14:06,833
which we wanna remove from the DOM.

287
00:14:07,760 --> 00:14:09,580
Of course, the downside of using this

288
00:14:09,580 --> 00:14:12,070
is that whenever we move that button

289
00:14:12,070 --> 00:14:14,420
into another level of nesting,

290
00:14:14,420 --> 00:14:16,960
we have to update the JavaScript code.

291
00:14:16,960 --> 00:14:20,790
But to practice DOM traversal and see how that works,

292
00:14:20,790 --> 00:14:24,350
and since I don't plan on changing the HTML structure here,

293
00:14:24,350 --> 00:14:26,113
I will use that approach.

294
00:14:27,180 --> 00:14:28,290
That means that here,

295
00:14:28,290 --> 00:14:31,680
where I do know that I wanna remove the item from the DOM,

296
00:14:31,680 --> 00:14:36,490
I'll use my buttonElement and access the parentElement

297
00:14:37,389 --> 00:14:40,538
and then access the parentElement of that

298
00:14:40,538 --> 00:14:43,750
and then access the parent element of that

299
00:14:43,750 --> 00:14:46,733
since accessing that first parentElement gives us

300
00:14:46,733 --> 00:14:48,850
that first div.

301
00:14:48,850 --> 00:14:51,930
Accessing the second parentElement here in the middle

302
00:14:51,930 --> 00:14:54,720
gives us that second div.

303
00:14:54,720 --> 00:14:57,290
And then accessing the parentElement here at the end,

304
00:14:57,290 --> 00:14:59,460
that gives us the article,

305
00:14:59,460 --> 00:15:02,410
and it's this article which I wanna remove.

306
00:15:02,410 --> 00:15:06,780
Actually, if we are precise, it's not the article.

307
00:15:06,780 --> 00:15:10,750
Instead, in all products, it's that list item.

308
00:15:10,750 --> 00:15:13,580
So we should actually go up one level more

309
00:15:13,580 --> 00:15:18,580
and access .parentElement again to access that list item.

310
00:15:19,180 --> 00:15:21,340
And, yeah, that can be a bit hard to read,

311
00:15:21,340 --> 00:15:25,810
but, again, I wanna practice this DOM traversal thing.

312
00:15:25,810 --> 00:15:29,720
And with that all done, we now got access to the list item

313
00:15:29,720 --> 00:15:31,950
that holds the article that we wanna remove,

314
00:15:31,950 --> 00:15:35,263
therefore we can now call remove on that.

315
00:15:36,290 --> 00:15:40,150
That's a built-in method that exists on DOM elements,

316
00:15:40,150 --> 00:15:42,550
and it will remove that element from the DOM

317
00:15:42,550 --> 00:15:44,063
when we call that method.

318
00:15:46,300 --> 00:15:49,010
Okay, so that should actually do the trick.

319
00:15:49,010 --> 00:15:50,730
Now we need to make sure

320
00:15:50,730 --> 00:15:55,640
that we actually do include that product-management.js file

321
00:15:55,640 --> 00:15:58,570
on this all-products page.

322
00:15:58,570 --> 00:16:01,050
So here in all-products.ejs,

323
00:16:01,050 --> 00:16:04,410
below this link I'll add a script import

324
00:16:04,410 --> 00:16:09,410
where my source is /scripts/product-management.js,

325
00:16:12,610 --> 00:16:14,750
and, as always, we defer this

326
00:16:14,750 --> 00:16:17,000
so that this only becomes active

327
00:16:17,000 --> 00:16:19,983
after the entire page content has been parsed.

328
00:16:21,740 --> 00:16:23,930
Now with that, if we reload this page,

329
00:16:23,930 --> 00:16:25,510
and we open the Dev Tools

330
00:16:25,510 --> 00:16:27,430
to see the JavaScript Console there

331
00:16:27,430 --> 00:16:29,730
to see any possible errors,

332
00:16:29,730 --> 00:16:33,453
if I click on this Keyboard item and the Delete button,

333
00:16:34,310 --> 00:16:35,800
I get an error.

334
00:16:35,800 --> 00:16:39,730
I get an error from the server, a 500 error,

335
00:16:39,730 --> 00:16:44,270
and hence my something went wrong pop up here.

336
00:16:44,270 --> 00:16:47,530
So let's see what's wrong by going to the server side

337
00:16:47,530 --> 00:16:50,860
where we see the server-side error message.

338
00:16:50,860 --> 00:16:53,970
It's invalid csrf token error.

339
00:16:53,970 --> 00:16:57,440
Now, if we reload, we see that it actually was deleted,

340
00:16:57,440 --> 00:16:59,740
so that actually worked,

341
00:16:59,740 --> 00:17:01,840
but, still, we got that error.

342
00:17:01,840 --> 00:17:05,010
But, actually, that error has a reason.

343
00:17:05,010 --> 00:17:08,119
If we click Delete on the Magic Trackpad here,

344
00:17:08,119 --> 00:17:09,910
and we have a look at the Network tab

345
00:17:09,910 --> 00:17:11,089
of the browser Dev Tools

346
00:17:11,089 --> 00:17:14,410
and clear that here before clicking Delete,

347
00:17:14,410 --> 00:17:17,250
we see that actually two requests are sent here.

348
00:17:17,250 --> 00:17:20,300
The first request is the correct one.

349
00:17:20,300 --> 00:17:23,339
It sends a request to that URL

350
00:17:23,339 --> 00:17:25,700
that includes the ID and the CSRF token,

351
00:17:25,700 --> 00:17:27,150
and it's this DELETE request.

352
00:17:28,069 --> 00:17:29,920
Then we got a redirect, though,

353
00:17:29,920 --> 00:17:32,920
because, of course, in my controller

354
00:17:32,920 --> 00:17:35,220
here on the backend, in the admin-controller,

355
00:17:35,220 --> 00:17:37,110
I am redirecting.

356
00:17:37,110 --> 00:17:38,530
Now, that's the problem.

357
00:17:38,530 --> 00:17:39,780
I am redirecting

358
00:17:39,780 --> 00:17:43,710
even though I'm sending a frontend-based JavaScript request.

359
00:17:43,710 --> 00:17:47,330
And the idea behind those JavaScript-driven requests

360
00:17:47,330 --> 00:17:49,250
is that we don't load a new page,

361
00:17:49,250 --> 00:17:51,580
but we stay on the existing page.

362
00:17:51,580 --> 00:17:55,560
Hence, by default, it doesn't support a redirect response,

363
00:17:55,560 --> 00:17:58,190
and that is in the end what causes this error here

364
00:17:58,190 --> 00:17:59,853
even though it's a bit cryptic.

365
00:18:00,840 --> 00:18:03,030
The proper thing to do here on the backend

366
00:18:03,030 --> 00:18:04,810
is not to redirect.

367
00:18:04,810 --> 00:18:07,730
But since we will target and trigger this action

368
00:18:07,730 --> 00:18:11,080
with help of an AJAX request,

369
00:18:11,080 --> 00:18:14,263
we wanna send back a response in JSON format.

370
00:18:15,170 --> 00:18:18,800
This can be done by calling the json method on response,

371
00:18:18,800 --> 00:18:21,530
and there, we can now pass object

372
00:18:21,530 --> 00:18:25,350
which will be transformed to JSON by Express

373
00:18:25,350 --> 00:18:27,340
where we, for example, just send a message

374
00:18:27,340 --> 00:18:29,880
like Deleted product

375
00:18:29,880 --> 00:18:32,773
since I don't really need any other response data.

376
00:18:33,680 --> 00:18:35,480
But now this is not a redirect

377
00:18:35,480 --> 00:18:37,800
but instead a different kind of response

378
00:18:37,800 --> 00:18:41,140
where we just respond with some data.

379
00:18:41,140 --> 00:18:44,300
And if you recall the section where I introduced you

380
00:18:44,300 --> 00:18:48,590
to AJAX and these frontend JavaScript-driven requests,

381
00:18:48,590 --> 00:18:52,380
you might recall that often the idea behind using AJAX

382
00:18:52,380 --> 00:18:54,500
is to just exchange data.

383
00:18:54,500 --> 00:18:57,360
That's what it's meant to be used for.

384
00:18:57,360 --> 00:19:00,520
So here we wanna send back such a data response

385
00:19:00,520 --> 00:19:03,450
using the commonly used JSON format

386
00:19:03,450 --> 00:19:06,030
which is supported out of the box by Express

387
00:19:06,030 --> 00:19:08,160
with help of that json method.

388
00:19:08,160 --> 00:19:11,830
And now with that, if we reload again,

389
00:19:11,830 --> 00:19:14,390
and we add a brand new product here quickly

390
00:19:14,390 --> 00:19:15,950
for testing this,

391
00:19:15,950 --> 00:19:19,290
just take any image and enter some dummy data,

392
00:19:19,290 --> 00:19:22,370
if I do that and I click Delete here,

393
00:19:22,370 --> 00:19:24,690
now it succeeds without an error message.

394
00:19:24,690 --> 00:19:27,460
And if I reload, this still works.

395
00:19:27,460 --> 00:19:29,940
And one last time, if I try this again

396
00:19:29,940 --> 00:19:34,170
and check if I got any error messages here in the Console,

397
00:19:34,170 --> 00:19:35,350
if I click Delete,

398
00:19:35,350 --> 00:19:37,560
no, that looks good.

399
00:19:37,560 --> 00:19:41,020
And that is how we can send such a deletion request

400
00:19:41,020 --> 00:19:43,470
with frontend JavaScript code

401
00:19:43,470 --> 00:19:46,713
and by using this AJAX request functionality.

