All language subtitles for 8. Refactoring for MVC

af Afrikaans
ak Akan
sq Albanian
am Amharic
ar Arabic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bem Bemba
bn Bengali
bh Bihari
bs Bosnian
br Breton
bg Bulgarian
km Cambodian
ca Catalan
ceb Cebuano
chr Cherokee
ny Chichewa
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
en English
eo Esperanto
et Estonian
ee Ewe
fo Faroese
tl Filipino
fi Finnish
fr French
fy Frisian
gaa Ga
gl Galician
ka Georgian
de German
el Greek
gn Guarani
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
id Indonesian
ia Interlingua
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
rw Kinyarwanda
rn Kirundi
kg Kongo
ko Korean
kri Krio (Sierra Leone)
ku Kurdish
ckb Kurdish (Soranรฎ)
ky Kyrgyz
lo Laothian
la Latin
lv Latvian
ln Lingala
lt Lithuanian
loz Lozi
lg Luganda
ach Luo
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mfe Mauritian Creole
mo Moldavian
mn Mongolian
my Myanmar (Burmese)
sr-ME Montenegrin
ne Nepali
pcm Nigerian Pidgin
nso Northern Sotho
no Norwegian
nn Norwegian (Nynorsk)
oc Occitan
or Oriya
om Oromo
ps Pashto
pl Polish
pt-BR Portuguese (Brazil)
pt Portuguese (Portugal)
pa Punjabi
qu Quechua
ro Romanian
rm Romansh
nyn Runyakitara
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
sh Serbo-Croatian
st Sesotho
tn Setswana
crs Seychellois Creole
sn Shona
sd Sindhi
si Sinhalese
sk Slovak
sl Slovenian
so Somali
es Spanish
es-419 Spanish (Latin American)
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
tt Tatar
te Telugu
th Thai
ti Tigrinya
to Tonga
lua Tshiluba
tum Tumbuka
tr Turkish
tk Turkmen
tw Twi
ug Uighur
uk Ukrainian
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
wo Wolof
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu

Original subtitles

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.