Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
1 1
Welcome back. 2
2
So now that you know everything 3
3
about the model-view-controller architecture 4
4
and also how it's gonna be implemented in our project, 5
5
let's now actually go do that in practice. 6
6
And this is gonna be a long lecture, 7
7
so let's get started. 8
8
And let's start by creating the necessary new files 9
9
so that we can then split up our code between them. 10
10
So let's start by closing all of the folders here. 11
11
And then inside of src 12
12
and JavaScript, let's create a new file, 13
13
which will be called model.js. 14
14
And so this is basically going 15
15
to be the module in which we write our entire model. 16
16
Then we also need the view, 17
17
or actually, the views 18
18
because we will have multiple views. 19
19
Basically one for each feature. 20
20
So now we're working on displaying the recipe 21
21
and so this one is going to be called recipeView. 22
22
But actually, let's create a new folder here 23
23
for the views in order not to clutter our JavaScript folder. 24
24
All right? 25
25
And so then in here, let's create recipeView.js. 26
26
So we will have one big module here 27
27
for all the controllers. 28
28
Then one big file for the entire model. 29
29
So for all the models basically. 30
30
So for the recipe, for search, for bookmarks 31
31
and all of that but for the views, 32
32
we will have one module for each of the different views. 33
33
And you'll understand why that makes sense 34
34
as we keep developing our application. 35
35
And probably the first reason that comes to mind 36
36
is that the views are simply much bigger. 37
37
And so we don't want a file, which like 500 lines of code. 38
38
We could, of course, also split up the model 39
39
and the controller and probably many people would do that 40
40
but I don't want to have to mess with a lot 41
41
of files here in this project. 42
42
That would just make it very confusing for you to follow. 43
43
So let's actually take a look again here 44
44
at this architecture 45
45
that I showed you in the last video. 46
46
And here, we will actually start with the model. 47
47
So again, we're going to have a big state object, 48
48
which then inside will contain an object for recipe, 49
49
search and bookmarks. 50
50
And now we will just start with the recipe 51
51
and then there will be a function 52
52
for loading the recipe, right? 53
53
And so then that function will then be called 54
54
by controlRecipes, which kind of sits 55
55
between loading the recipe 56
56
and then rendering it using the view. 57
57
So remember that the controller kind of sits 58
58
between model and the view 59
59
so it acts like a bridge. 60
60
All right, and let's actually keep it open here 61
61
and close all of these others. 62
62
And so here in our model, 63
63
let's simply create that state object 64
64
and then in there we have the recipe, 65
65
which in turn, is also an empty object. 66
66
At least at the beginning. 67
67
And then we will export this state 68
68
so that we can then use it in the controller. 69
69
And let's put them here just like in the diagram. 70
70
Model, controller and view. 71
71
Okay? 72
72
So we're exporting the state from here 73
73
and now let's also create that loadRecipe function. 74
74
And of course, we also export it 75
75
so that we can use it in the controller. 76
76
So loadRecipe. 77
77
And this function will be the one responsible 78
78
for actually fetching the recipe data 79
79
from our Forkify API. 80
80
And so this is going to be an async function. 81
81
All right? 82
82
And so now we can actually start grabbing some 83
83
of the code from here. 84
84
Okay? 85
85
So as I said, basically the goal of this lecture 86
86
is to refactor all the code here 87
87
into the different parts of the architecture. 88
88
Okay? 89
89
So what here exactly is concerned 90
90
with basically getting the data? 91
91
So it starts here 92
92
when we fetch the recipe from the API 93
93
and then basically, it's all of this here. 94
94
So all of this. 95
95
So let's copy it. 96
96
So rendering the spinner, of course, 97
97
has nothing to do with the business logic 98
98
but really, it is only presentation logic 99
99
and so this one will eventually go 100
100
into the view. 101
101
And then here getting the ID, 102
102
this is also not business logic. 103
103
This is actually more about the application logic itself. 104
104
So about making the application work. 105
105
And so let's keep that part here. 106
106
So again, I will just copy this 107
107
or actually cut and put it here. 108
108
And now we start getting these errors but nevermind. 109
109
Probably, we should actually terminate our process here 110
110
with Control + C 111
111
so that we don't get errors all the time. 112
112
Okay? 113
113
Now we need to, of course, adjust this here a little bit. 114
114
So this first part here makes sense, right? 115
115
Now, we just need to get this ID from anywhere. 116
116
So right now, we have no idea 117
117
which ID we should actually fetch. 118
118
And so it's probably a good idea 119
119
to pass that ID into this function. 120
120
So the controller is the one 121
121
that will actually get that ID right here 122
122
and so then when it calls the model, 123
123
so the loadRecipe function, 124
124
it can pass that ID into it. 125
125
Then this part here can all stay the same 126
126
and this as well. 127
127
And this actually should now 128
128
not be the recipe but state.recipe. 129
129
And here we can just create a const from this. 130
130
And here let's also log state.recipe. 131
131
All right. 132
132
So this function here is not going to return anything. 133
133
All it will do is to change our state object. 134
134
So this big state object, 135
135
which will then contain the recipe 136
136
and into which the controller 137
137
will then grab and take the recipe out of there. 138
138
And this is going to work 139
139
because there is a live connection 140
140
between the exports and the imports. 141
141
Remember that? 142
142
So when this state object here 143
143
is going to get updated by loadRecipe, 144
144
then that state is also updated in the controller, 145
145
which imports the state. 146
146
So let's now actually import all of that into here. 147
147
So doing it here at the very top. 148
148
So import and then from the model, 149
149
we simply want to import everything. 150
150
So we have a couple of named exports here. 151
151
So again, there are named exports 152
152
and default exports 153
153
and these ones are named exports 154
154
because we explicitly gave them a name 155
155
and so here we can simply import everything 156
156
and then call it the model. 157
157
And so here in the controller, 158
158
we will then end up with model.state 159
159
and model.loadRecipe. 160
160
Remember that? 161
161
And then here, the current folder, model.js. 162
162
Okay. 163
163
So let's go back here to loading the recipe 164
164
and the spinner should probably be outside of here. 165
165
And so here, now let's actually call the function. 166
166
So let's call model.loadRecipe 167
167
and then pass in the ID. 168
168
And this loadRecipe function 169
169
is an async function and therefore, 170
170
it is going to return a promise. 171
171
Remember? 172
172
And so therefore, here we have to avoid that promise 173
173
before we can move on in the next step here 174
174
in the execution of this async function. 175
175
And so you see, this is exactly the situation 176
176
of one async function calling another async function 177
177
that we already studied in one of the previous sections. 178
178
Remember that? 179
179
And so again, it is really, really important 180
180
to keep in mind that an async function 181
181
will return a promise 182
182
that we then need to handle 183
183
whenever we call that async function. 184
184
At least, if we want to get some result out of it 185
185
or if we kind of want to stop the execution 186
186
in the function that is calling the other async function. 187
187
All right? 188
188
So again, really important to understand the mechanics 189
189
of what is happening here. 190
190
Now, here we should probably also have some error handling. 191
191
So I forgot that part. 192
192
So try 193
193
and all the way down here, 194
194
and then catch the error 195
195
and then alert the error as well. 196
196
All right. 197
197
So remember that this loadRecipe function here 198
198
does not return anything. 199
199
And so therefore, we are not storing any result 200
200
into any new variable. 201
201
Instead, here we will get access 202
202
to state.recipe. 203
203
So to that state.recipe 204
204
that is going to be manipulated right here. 205
205
So you see that this loadRecipe function here clearly 206
206
is not a pure function. 207
207
So it has the side effect 208
208
of manipulating this variable 209
209
that is outside of it. 210
210
And there would be different ways 211
211
of avoiding that but that is just a lot of work 212
212
and it's just not worth it here in this case. 213
213
We are still trying to learn here, remember. 214
214
But anyway, we now here have access 215
215
to model.state.recipe. 216
216
And so just in order to see 217
217
if everything still works, 218
218
let's store that recipe into the recipe variable 219
219
so that we can then render it, 220
220
using this code that we already have here. 221
221
So just temporarily, recipe 222
222
and then destructure it. 223
223
So let's give it a save 224
224
and let's restart our application here. 225
225
All right. 226
226
Let's reload here 227
227
and you see that it's working. 228
228
Right? 229
229
So everything we implemented so far was correct 230
230
and that's pretty important to keep checking 231
231
when we are refactoring code like this. 232
232
Okay? 233
233
So that was actually the easy part, 234
234
now comes the recipeView, 235
235
which will then contain basically all the rest 236
236
of the code that we have here. 237
237
So let's go here and set the view up. 238
238
So the view is going to be a class 239
239
and in this case called RecipeView. 240
240
And we do this because later, 241
241
we will also have a parent class called View, 242
242
which will contain a couple of methods 243
243
that all the views should inherit. 244
244
And so using classes makes all 245
245
of this very simple to implement. 246
246
Also, we want each view to have a couple of private methods 247
247
and properties and so classes makes this really easy 248
248
to implement again. 249
249
And just in general, I feel that classes 250
250
are really the right way to go here. 251
251
And again, it will make even more sense 252
252
once we start to add the parent class of view. 253
253
But anyway, I mentioned that I want each 254
254
of these classes to have a couple of private properties 255
255
and one of them is going to be the parentElement. 256
256
So parentElement, and let's right away set the parentElement 257
257
to the recipe container. 258
258
So basically, to this element, all right? 259
259
Because this will then make it really easy 260
260
to render the spinner 261
261
and to render success or error messages 262
262
or to render, of course, the recipe itself. 263
263
So if each of the views has this parentElement property, 264
264
then it will be really easy to do all of those tasks 265
265
and again, that will become really clear 266
266
once we start adding more and more views. 267
267
But now the next thing I want to do 268
268
is to actually export something from this module. 269
269
So of course, we have to export something 270
270
from this view so that the controller 271
271
can then use it. 272
272
Now, what are we going to export from this view? 273
273
So we might export, of course, 274
274
the entire class like this 275
275
and so then here in the controller, 276
276
we would have to import that class 277
277
and create a new object out of that class. 278
278
So basically, create a new RecipeView object, right? 279
279
However, in that situation, 280
280
it might be possible 281
281
to create more that one view 282
282
and we would never want that. 283
283
Also, that would add unnecessary work 284
284
to the controller, which we basically want 285
285
to keep as simple as possible. 286
286
And so in order to avoid all that, 287
287
we will already create the object here 288
288
and then export that object. 289
289
And so like this, no one from the outside 290
290
of this class here will have access to anything, 291
291
except for the object. 292
292
So what we will do is to export default 293
293
and then a new RecipeView. 294
294
All right? 295
295
And that's actually it. 296
296
So we don't pass any data in 297
297
and so therefore, we don't need any constructor even. 298
298
Okay? 299
299
And then here all we do is import 300
300
and here we then can give it any name. 301
301
So I'm calling it recipeView 302
302
because I think that's what makes most sense. 303
303
And then views and then recipeView.js. 304
304
Now, how do we then actually pass any data 305
305
into the recipeView? 306
306
Because if we're not creating the new object ourselves, 307
307
then we cannot pass any data 308
308
in like for the constructor, right? 309
309
So we cannot pass any data into this RecipeView, 310
310
well, because we're creating that object right here 311
311
in the RecipeView module already. 312
312
But actually, I did that on purpose 313
313
so that we can create a very nice method called render. 314
314
So what I will want to do here, 315
315
and let me already write it here 316
316
even before having the method. 317
317
So what I will want to do is to call recipeView.render. 318
318
And then here all we do is to pass in the data, 319
319
which will be model.state.recipe. 320
320
And this method here called render 321
321
is a very common name for methods, 322
322
for example, in React, it is also called render. 323
323
And so I think this is a nice name. 324
324
It's really descriptive of what is going to happen. 325
325
All right? 326
326
So if we did export the entire class, 327
327
then here we would have to do like const recipeView 328
328
equal new RecipeView or something like that. 329
329
And then here, we would have to pass in the data like this 330
330
when we create the new recipe. 331
331
And of course, this would also be possible 332
332
but honestly, I like it better like this. 333
333
So having this nice render method 334
334
is a lot more descriptive 335
335
and a lot cleaner and also for the reasons 336
336
that I explained previously already. 337
337
Now, anyway, this render method here 338
338
will now accept this data. 339
339
It will then store it into the object. 340
340
So let's add the public render method. 341
341
So this is, of course, part of the public API. 342
342
So this receives data 343
343
and will then set this.#data 344
344
to the data it just received. 345
345
So we need to declare that up here. 346
346
And so this render method here 347
347
and these two properties 348
348
are something that all the views 349
349
are going to have in common. 350
350
And this will be really beautiful to work with 351
351
as you will see. 352
352
But now, let's actually do something with this data, 353
353
which is to actually render it. 354
354
So basically what we want now 355
355
is to take all of this code 356
356
and cut it from here. 357
357
And put it into our view. 358
358
Okay? 359
359
Now, we will actually not put it into the render method 360
360
because again, this method will later be common 361
361
to all the views. 362
362
So to all the classes. 363
363
However, each view will, of course, render different HTML. 364
364
And so we will simply have a method 365
365
that generates that HTML 366
366
so that the render method can then render that HTML. 367
367
So if that sounds confusing, let me write it in code. 368
368
So generateMarkup. 369
369
And so this is going to be a private method 370
370
and since we're using Babel here, 371
371
I can already use this syntax here. 372
372
So pasting the code here 373
373
and so this is going to generate this Markup variable 374
374
and we can actually immediately return that from here. 375
375
Okay? 376
376
Now, this is not going to do anything yet 377
377
because what is recipe here in this case? 378
378
It's nothing, right? 379
379
It's not defined at all. 380
380
Now, in this case, where is this data actually? 381
381
Well, it is in this.#data, right? 382
382
So why's that? 383
383
So let's take a look at our controller 384
384
and let's start from the beginning. 385
385
So the recipe is loaded here 386
386
and then that will store it into the state object, right? 387
387
Here we don't need that anymore. 388
388
Then here we take model.state.recipe, 389
389
which is that data that we just received here in step one 390
390
and then that data is passed into the render method, right? 391
391
And so render method then takes that data 392
392
and stores it inside of this.#data. 393
393
And so this is so that we can then use 394
394
that data all over the place 395
395
inside of this object. 396
396
And by the way, this is exactly what we have here 397
397
in this architecture diagram. 398
398
So inside of controlRecipes, 399
399
the loadRecipe function is called, 400
400
then the recipe data foes into the state 401
401
and then that data passes 402
402
right through the controller basically 403
403
and goes into the render method, 404
404
which then in turn, calls generateMarkup. 405
405
So you see, we already have many things 406
406
here implemented here already, 407
407
like data and parentElement, 408
408
we're just missing some small parts 409
409
but we are going to get there. 410
410
But now what we were doing here 411
411
is to discuss where this recipe data 412
412
is actually located right now. 413
413
And we came to the conclusion that it is in this.#data. 414
414
So I will copy it 415
415
and then we need to replace all the recipe. here with that. 416
416
So I'm hitting Command + D. 417
417
So for you, that should be Control + D. 418
418
And then let me paste that dot 419
419
and then that's it. 420
420
All right? 421
421
Then down here, we have this code, 422
422
which is not supposed to be here 423
423
because all this function does 424
424
is to return an HTML string. 425
425
And it's going to be the render method 426
426
that will be responsible for then actually putting 427
427
that HTML onto the page. 428
428
Now, okay. 429
429
So here, let's say that the markup 430
430
is this.#generateMarkup. 431
431
Well, this is probably something that's coming 432
432
from Babel here. 433
433
Not really sure why. 434
434
But apparently, VS Code doesn't like this yet. 435
435
Ah, we're still missing the dot here, of course. 436
436
Now it appears to be working. 437
437
And of course, we've still got some errors here 438
438
but nevermind about that. 439
439
We are still refactoring. 440
440
So we have our markup. 441
441
Now we need to put it on the page. 442
442
So again, we need to start by clearing the parentElement 443
443
and actually, let's create another small method for that. 444
444
So just to get in the habit of abstracting some code 445
445
and so now this is where our parentElement 446
446
will come into play 447
447
'cause now we can say 448
448
this.#parentElement.innerHTML 449
449
and set it to empty. 450
450
Right? 451
451
And so this method here 452
452
will be usable for all the views 453
453
as long as all the views 454
454
have a parentElement property like this one. 455
455
Right? 456
456
So all of this will become really reusable 457
457
as you will in one of the future lectures. 458
458
So here we now can then call that. 459
459
And then to finish, 460
460
we can finally render that HTML to the page. 461
461
And so here, once again, 462
462
we can now use this.#parentElement 463
463
and then insert that HTML there. 464
464
Okay. 465
465
So this might already be working actually. 466
466
So all of this here looks good to me. 467
467
Let's take a look at the controller. 468
468
And you see that this is now a really nice 469
469
and small function here already, right? 470
470
Now, this one, we actually want to call it controlRecipes. 471
471
So let's replace it everywhere. 472
472
controlRecipes. 473
473
So that's the name that I have here in the diagram. 474
474
Okay? 475
475
And so now what we're missing 476
476
is only to export the renderSpinner also into the view. 477
477
So this one, of course, 478
478
also has nothing to do with the controller 479
479
and so it belongs in the view. 480
480
So of course, not a function 481
481
but a method and this one will also be a public method 482
482
so that the controller can then call this method here 483
483
as it starts fetching the data. 484
484
Okay? 485
485
And now here again, 486
486
we have the beauty of the parentElement already being 487
487
inside of the object. 488
488
So this one we can simply delete 489
489
and here we can replace it with this.#parentElement. 490
490
Now, right. 491
491
Next up, I'm seeing that this icons variable 492
492
is not going to be defined anywhere in this module. 493
493
So we will need to grab that from here. 494
494
So you'll see that here we have the icons 495
495
and we don't need them here anymore at least. 496
496
So now we need them right here. 497
497
And now what we need to do 498
498
is to then call this renderSpinner method right here. 499
499
So that's going to be recipeView.renderSpinner 500
500
and here again, we no longer need to pass 501
501
in the parentElement. 502
502
And just watch how beautiful this is. 503
503
So we have recipeView and then renderSpinner 504
504
and we already know 505
505
that this will then automatically render the spinner 506
506
on the recipeView. 507
507
And the same is later going to happen with other views. 508
508
For example, with the bookmarks view. 509
509
We will also have a renderSpinner on the bookmarks view 510
510
and it's going to work the exact same way. 511
511
And the same with render. 512
512
So all we have to do is call these same methods then 513
513
on all the views 514
514
and they will then simply act on whatever view 515
515
that we are calling them, right? 516
516
And that works so nice 517
517
because we have this parentElement here 518
518
and also this data property. 519
519
So I think that this is a really nice architecture 520
520
and so let's now actually see if this works. 521
521
So let's reload this here. 522
522
And here we have some errors. 523
523
So apparently, if there is a really big error, 524
524
then Parcel will let us know about that. 525
525
And in this case, the problem is that it failed 526
526
to resolve this URL. 527
527
And that actually makes sense 528
528
because this view here is in a different folder. 529
529
Right? 530
530
So here we're only going one folder up 531
531
and going up one folder from here 532
532
will end up in the JavaScript folder. 533
533
However, we want to go into images. 534
534
So we need to go up one more level. 535
535
So like this. 536
536
Okay? 537
537
So here we have apparently some bug. 538
538
Let's just see if anything happens still on this event 539
539
and it does. 540
540
There's still some problem here maybe 541
541
that has to do with the fact 542
542
that we are using these private methods here. 543
543
So let me change this here 544
544
to this one. 545
545
So right here, yeah. 546
546
And let's also comment out this one 547
547
and then we're not using any private methods anymore. 548
548
However, that is apparently still not working. 549
549
All right. 550
550
So let's take a look here at our this.#data. 551
551
So this.#data just to see what we get here. 552
552
And so we see that apparently 553
553
that method is not even being called. 554
554
Ah, and I see the problem. 555
555
I actually did not call it. 556
556
So I didn't use the parenthesis, right? 557
557
So what a stupid mistake. 558
558
So let's roll back on all the changes I did, 559
559
except, of course, for this one 560
560
but here, probably all I need to do 561
561
is to call these two methods. 562
562
Ah, beautiful. 563
563
So we're back. 564
564
It's working now again. 565
565
And it's working really nice, 566
566
including the spinner. 567
567
Okay? 568
568
And so I think with this, 569
569
we successfully refactored our entire code 570
570
to this new architecture. 571
571
Well, not the entire code actually. 572
572
We're still missing this handler here 573
573
and all of this part that is here. 574
574
But don't worry about that for now, okay? 575
575
We will have a separate lecture, 576
576
which will talk about how we can handle events 577
577
in this particular architecture. 578
578
For now what matters 579
579
is that this works just nicely. 580
580
There's just one thing that I actually want to change 581
581
but that has nothing to do with the architecture. 582
582
So what I want to change is these numbers. 583
583
So do you see here we have 0.5 584
584
but in the real world, you will see this more like this. 585
585
So like 1/2 tablespoon of brown sugar 586
586
instead of 0.5. 587
587
So this looks a lot nicer or this, for example, 588
588
1 1/2 is a lot nicer than 1.5. 589
589
And so for that, 590
590
we are actually going to use an external library, 591
591
which will very easily do this for us. 592
592
Okay? 593
593
And so I included this part so I could show you 594
594
just how to do this. 595
595
So let me just google it here. 596
596
Npm fractional 597
597
just so we can see what this package looks like. 598
598
So if you google npm, 599
599
then you will usually end up on npmjs.com 600
600
and this will then contain like one page 601
601
for each package that is on npm, all right? 602
602
And so here what you see 603
603
is that you can basically create new fractions based 604
604
on numbers and then you can do all kinds of multiplications 605
605
with them, like multiplying, dividing 606
606
and in the end, converting them to a string. 607
607
And so that's what we will do now. 608
608
So we will convert each number to a fraction 609
609
and then immediately convert them to a string. 610
610
So this is how we install it. 611
611
Let's just grab that. 612
612
And then we need our terminal back. 613
613
Let's add another one. 614
614
So that's the plus sign. 615
615
And this should be pretty fast hopefully. 616
616
And so we need that here 617
617
and so let's import 618
618
fractional from 619
619
and then fractional. 620
620
And so here again you see 621
621
that any libraries or any packages 622
622
that we import from npm, 623
623
we don't even have to specify any path. 624
624
All we have to do is to write their names here 625
625
and then here, we need also what they export. 626
626
And let me see what they actually export. 627
627
So it should be called fraction, okay? 628
628
So this library actually exports something called fraction. 629
629
And we can see that because here, 630
630
it is importing the fractional library using require. 631
631
And that is simply the old CommonJS way of importing, 632
632
which I showed you earlier. 633
633
And so that is one of the reasons 634
634
why I show that to you 635
635
because yeah, again you will see this all the time 636
636
in the wild still 637
637
because so many packages on npm 638
638
are still using CommonJS. 639
639
So let's import Fraction here. 640
640
Actually like this. 641
641
Okay? 642
642
And let's just see if this actually does exist now. 643
643
And yeah, it does. 644
644
So actually, that's even Fraction inside of Fraction 645
645
but anyway, let's now go ahead and use this actually 646
646
so that it's in here. 647
647
So here we now no longer simply want the quantity 648
648
but we want the quantity converted 649
649
to a fraction string. 650
650
So according to the documentation, 651
651
we have to say new Fraction 652
652
and in this case, it's actually Fraction.Fraction. 653
653
So again that's because here inside of Fraction 654
654
is where the Fraction function is actually located. 655
655
Okay? 656
656
And here you could see that we have to then use new. 657
657
Now, actually to make this a bit nicer, 658
658
we can also use destructuring here right away. 659
659
So we can do this. 660
660
And if we now take a look, 661
661
well, now we have this bug here. 662
662
But nevermind. 663
663
So let's just do this. 664
664
And then call toString on that 665
665
just like it said in the documentation. 666
666
So you see that now as I destructured that fraction, 667
667
it became the actual function. 668
668
And yeah, here you see beautifully that it is now 669
669
in this size or in this format of the fraction. 670
670
And if I take a look at the other one, 671
671
then the same as well. 672
672
Now, this one doesn't look very beautiful but nevermind. 673
673
So we cannot fix all of it 674
674
but at least, this looks really cool now, right? 675
675
And so this is when we reach for packages on npm. 676
676
So when we need some functionality 677
677
that we don't want to implement ourselves. 678
678
I'm just going back here 679
679
because I noticed some problem here, 680
680
which was this one. 681
681
And that was because previously here we had null. 682
682
So there was no value for this cilantro. 683
683
And so we should probably check if the number does exist. 684
684
So we can say ing.quantity. 685
685
If it exists, then do this. 686
686
And if not, then simply put an empty string there 687
687
and of course, now here. 688
688
So that must be out here. 689
689
Yep, now it's gone and it looks a lot nicer. 690
690
All right. 691
691
Now just to finish, 692
692
I actually want to refactor this function here. 693
693
So let me grab this 694
694
and put it down here and call it generateMarkupIngredients 695
695
or just Ingredient. 696
696
Okay. 697
697
And this will then receive the ingredient. 698
698
Okay. 699
699
And then here inside of the map, 700
700
we can then simply call this. 701
701
And let's copy it because these private methods, 702
702
for some reason, VS Code doesn't really understand them yet. 703
703
So right here. 704
704
And so successfully refactored this part 705
705
and so we are now done in this lecture 706
706
where we also successfully refactored the entire code 707
707
that we already had 708
708
to the model-view-controller architecture. 709
709
All right? 710
710
So we're not done 100% 711
711
but we've done a lot of work in this lecture 712
712
and I really hope that you understood everything 713
713
that we did here. 714
714
So this was a really, really, really important lecture. 715
715
So make sure that you understand everything that we did. 716
716
So make sure to review all the code 717
717
and also compare it here 718
718
with this diagram one more time 719
719
so that you see which functions we call when 720
720
and then also, how exactly the data flows 721
721
between these different functions. 722
722
And especially here in this view 723
723
because I know that this can get a little bit confusing 724
724
and so reviewing this 725
725
is gonna be a very good idea, 726
726
especially because we will use this so many times also 727
727
in the other features. 728
728
And so by then, you really must understand 729
729
how all of this fits together 730
730
because otherwise, it's gonna be very hard 731
731
to follow the rest of the project. 732
732
Okay, so take your time 733
733
and only then move on to the next video.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.