All language subtitles for 13. Implementing Search Results - Part 2

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

Let's now render the search results 2

2

by creating a new view. 3

3

So we already have the searchView 4

4

but now we also want to create like a resultsView. 5

5

So a resultsView, which will contain a render 6

6

so that we can then call that render here 7

7

with these search results. 8

8

So similar to what we have here, 9

9

so to the recipeView, 10

10

which also has a render method, 11

11

which takes in some data 12

12

and so now, again we want the same 13

13

for a results view. 14

14

So we also want it to have a render method, 15

15

which takes in data and which is then rendered 16

16

to our user interface. 17

17

So let's create the resultsView.js. 18

18

So ResultsView 19

19

and so now this view 20

20

will actually be pretty similar to the recipeView. 21

21

So we don't need that one anymore. 22

22

But now, again this one is going 23

23

to be very similar. 24

24

So we will have a parentElement, 25

25

data, these messages. 26

26

We will basically also need the same render method, 27

27

the same renderSpinner. 28

28

So we will need to display the spinner 29

29

while the data is being fetched, 30

30

so in this case, the search results. 31

31

We might need to also render an error 32

32

and so now it's time to basically refactor this code 33

33

and create a parent class. 34

34

So I had mentioned that before 35

35

but now it's actually time to do it 36

36

because by creating a parent class, 37

37

we will then be able to reuse all of these methods 38

38

on all the views. 39

39

So basically, on all the objects 40

40

that are created through all the view classes. 41

41

So let's create yet another file here 42

42

and I'm calling it View.js. 43

43

And so let's create a new class here called View 44

44

and so we will then export immediately this class. 45

45

And actually, let's make it a default export. 46

46

So at this time, we are actually exporting the class itself 47

47

because of course, we are not going to create any instance 48

48

of this view. 49

49

We will only use it as a parent class 50

50

of these other child views, all right? 51

51

Here in the recipeView, 52

52

let's now import that parent class. 53

53

So import View as, 54

54

or actually, not as but from View 55

55

and actually, we don't even need the js 56

56

but I like to keep it there for consistency. 57

57

And so now, all we need to do 58

58

is to basically copy everything 59

59

that should be common to all the views 60

60

to that parent class. 61

61

However, there is one thing 62

62

that we still need to change here. 63

63

And that is that right now, 64

64

with Parcel and Babel, 65

65

inheritance between these truly private fields 66

66

and methods doesn't really work yet. 67

67

So here it was nice to actually use the native way 68

68

of JavaScript of protected methods and properties 69

69

but now we cannot really use it anymore. 70

70

So maybe that might be possible at some point in the future 71

71

but for now, we will have to go back to protected fields 72

72

and protected methods. 73

73

So let's basically select all of these hash symbols 74

74

and actually, I will select them like this. 75

75

So with the dot because otherwise, 76

76

that will also select these ones. 77

77

So hitting Command + D here a couple of times. 78

78

And then replace it with ._ 79

79

and now we just have to change these method names. 80

80

So changing from truly private 81

81

to only protected using the underscore convention. 82

82

And then the same right here. 83

83

Okay? 84

84

So now our code should still be working. 85

85

It says here connection lost 86

86

but indeed, our code keeps working here. 87

87

Okay? 88

88

Let's just check out the search view 89

89

and so let's use the same convention here as well. 90

90

Okay. 91

91

Just here as well. 92

92

And now here we also converted everything successfully. 93

93

But anyway, let's now basically extract the View class 94

94

from this RecipeView. 95

95

So what we need in all the views 96

96

is this render method, 97

97

then this one as well, this one, 98

98

and basically everything except for generating the markup 99

99

because that, of course, 100

100

is gonna be unique to every single view, right? 101

101

And also, adding the handler. 102

102

But everything else we want to be the same on all the views. 103

103

For example, rendering a spinner 104

104

will be really easy. 105

105

So all the views will simply have this method 106

106

and we will then be able to call it on that method 107

107

and thanks to the parentElement property here, 108

108

it will then know exactly 109

109

to which element it should attach the spinner 110

110

because again, the parentElement, 111

111

of course, will be unique to each single view. 112

112

So the parentElement will be unique, 113

113

the message, so these two messages 114

114

but this data can actually also be on the parent. 115

115

So let's copy all of this here or actually cut. 116

116

So everything except for adding the handlers 117

117

and generating the markup. 118

118

So let's put that here. 119

119

And here we, of course, then need to extend this one. 120

120

So extends View. 121

121

Right? 122

122

And so let's see if we have everything still in place. 123

123

Yeah, so I'm confident that this will work now. 124

124

So let's see. 125

125

Oh, and icons is not defined. 126

126

So let's go back here to our view 127

127

where we will have to copy this one. 128

128

Because here, of course, we are also using the icons. 129

129

Okay. 130

130

But here it is. 131

131

All right? 132

132

So we successfully extracted the View class 133

133

from the recipeView. 134

134

And now all that's left here 135

135

is really what is unique to this view. 136

136

And so this makes this even easier to work with 137

137

in my opinion because now let's see what we can do here. 138

138

So even without any code yet in the results view, 139

139

we will already be able to add a spinner 140

140

to the search results. 141

141

All right? 142

142

Well, we cannot really leave it empty. 143

143

We still need actually the parent element here. 144

144

All right? 145

145

And we also need to import the View. 146

146

So import View 147

147

and then this is just another child class of View. 148

148

Then here, we need to say that parentElement 149

149

should be well, something. 150

150

And let's check out what it actually should be. 151

151

So here in index, 152

152

let's see. 153

153

So it's this here. 154

154

So this results element, so this unordered list. 155

155

All right, and then basically, 156

156

each of the search-results will be one 157

157

of these preview elements. 158

158

But more about that later. 159

159

So for now, let's just set the parentElement 160

160

to this results element here in resultView. 161

161

So document.querySelector results. 162

162

And then we have to export 163

163

default just like before 164

164

and then a new instance of this view. 165

165

And so this way they can only be one ResultsView 166

166

and then here in controller, 167

167

we can immediately import that 168

168

without having to create the instance here manually. 169

169

So that's resultsView like this. 170

170

And so now here we should already be able 171

171

to load the spinner 172

172

or actually to display the spinner. 173

173

So let's do that at the very beginning. 174

174

So resultsView.renderSpinner. 175

175

And let's see what happens. 176

176

So pizza and here is a small error 177

177

and so let's once again do some debugging here 178

178

and I hope that you can appreciate 179

179

that I'm actually not cutting out 180

180

all these like small debugging sessions 181

181

so that you can actually see 182

182

what I'm doing here. 183

183

But anyway, apparently the problem appears here in View.js 184

184

at line 14. 185

185

So right here. 186

186

So it seems like it cannot find the parentElement. 187

187

So let's simply log that to the console. 188

188

So this here is the result of doing that for the view. 189

189

And now let's see. 190

190

So now that is undefined. 191

191

So to me it seems 192

192

like here we selected the wrong element here maybe. 193

193

So results. 194

194

So that should actually 195

195

be correct. 196

196

And so should the name. 197

197

So I think parentElement is correctly spelled. 198

198

Oh, but it's actually called parentElement all written out. 199

199

Okay. 200

200

So you see, it's actually called parentElement like this. 201

201

For some reason, I thought it was called 202

202

just like the abbreviation. 203

203

Ah. 204

204

And you see, here is the nice loading spinner, 205

205

spinning away here in our search results. 206

206

Right? 207

207

And again, all without writing any new code 208

208

for displaying that spinner here in the ResultsView 209

209

because it is now simply inheriting that method 210

210

so that renderSpinner method from its parent class. 211

211

So let's get rid of this 212

212

and just for the sake of curiosity, 213

213

let's actually take a look 214

214

at this resultsView, 215

215

so just so we can see the whole prototype chain here 216

216

in the console. 217

217

So for that, we need that controller to run 218

218

and so here it is. 219

219

So you see that we have still some undefined data. 220

220

Then we have the parentElement. 221

221

So the one we selected. 222

222

And then we get, 223

223

well, right now, we don't have any methods 224

224

in the class already 225

225

but we do have methods in a parent class. 226

226

And so these are the ones. 227

227

Right, so the render one that we're gonna use next, 228

228

then renderError and Spinner and Message. 229

229

So it's always good to remember these things 230

230

so that we still know how everything still actually works 231

231

behind the scenes. 232

232

But now it's actually time 233

233

to create basically this generateMarkup method also 234

234

in the resultsView, okay? 235

235

So all the child views should have this method here 236

236

because in the view, the render method then actually relies 237

237

on that, okay? 238

238

So this.generateMarkup needs to exist in order 239

239

for the render method then being able 240

240

to create the markup and render it 241

241

or to insert that HTML into the DOM. 242

242

And so let's take that, just that name 243

243

and create that right here. 244

244

So as always, a template literal 245

245

and then now it's time to actually get this code here. 246

246

Okay? 247

247

And this here is called a preview 248

248

because we will actually use the same thing later here 249

249

to render the bookmarks. 250

250

So that's gonna be a nice trick 251

251

but we will save that for the future. 252

252

Okay? 253

253

Some more indentation here on all of this 254

254

to make it look great. 255

255

And so now we need to take our data 256

256

and actually put that right here. 257

257

Now, where actually is that search results data? 258

258

So with all of the structure, 259

259

it might be a little bit hard to follow 260

260

where that data is. 261

261

So let me actually start 262

262

by calling the render method here. 263

263

So here, besides of simply logging the search results, 264

264

we now also want resultsView.render 265

265

because of course, just like renderSpinner, 266

266

the resultsView also inherits render 267

267

and then into that, we pass whatever we want to be rendered. 268

268

And so that is all of this. 269

269

Okay? 270

270

And then in the render, 271

271

here we see that it takes this data 272

272

and puts it into this._data. 273

273

And so here, if we then take a look at the resultsView, 274

274

let's simply log that then to the console. 275

275

So this._data 276

276

and so this_data here 277

277

should basically be exactly this search.results. 278

278

So let's see. 279

279

And it is. 280

280

So you see that twice we now get this array 281

281

and you also see that it already printed something here 282

282

to the results. 283

283

So that is that pre-formatted HTML 284

284

that we already created here. 285

285

So it's already basically this HTML, right? 286

286

Because this method here is already returning that 287

287

and so then the view takes that data 288

288

and renders it on the user interface. 289

289

Okay? 290

290

And so let's now actually create this method. 291

291

Now, this is actually an array now 292

292

and so here we need to loop over that array. 293

293

So in fact, we don't want to return simply this 294

294

but instead, we want to return a whole string, 295

295

which contains like one of these elements 296

296

for each of the search results in the array. 297

297

So we will return basically this._data 298

298

and then we map over it. 299

299

Remember, so we did that before with the ingredients 300

300

and then at the end, 301

301

we join everything together 302

302

and so then that will be the string 303

303

that we return here. 304

304

Now, we could now go ahead 305

305

and put this code here into the map function 306

306

but instead, I will create just another method down here 307

307

to make this a little bit cleaner. 308

308

Let me copy this name. 309

309

Preview. 310

310

And I'm simply calling it this 311

311

because that's also the class name. 312

312

So let's put this one here. 313

313

And so then here we can call the method. 314

314

Oh, what was that? 315

315

So we can call it right here then. 316

316

And so now this should like print 50 or 60 of the same. 317

317

So just to see if it works. 318

318

And indeed, here it is. 319

319

So 59 results 320

320

and so it prints this 59 times right here now. 321

321

Right? 322

322

Now, all we need to do is to fill it 323

323

with the real data. 324

324

So with the id, image, publisher and title. 325

325

Okay? 326

326

So to start, we need the ID here 327

327

in order to build the link 328

328

and so then we click the link, 329

329

that will change the hash in the URL, 330

330

which in turn, will trigger a loading a recipe. 331

331

So that's what we did by the beginning of this section. 332

332

Now, here we need to pass in the result then. 333

333

And so here that is result.id. 334

334

Then here it's the image, 335

335

so .image. 336

336

Here it's the title. 337

337

And then here the publisher. 338

338

Okay. 339

339

Here we also need to replace the icons. 340

340

So we will need again the icons right here. 341

341

We will probably need them in all of them. 342

342

But that should be it. 343

343

And it works. 344

344

Beautiful. 345

345

So we get all of these search results here. 346

346

We just have to fix some small details 347

347

but you see that it's already working 348

348

and now let's click on one of them and it works. 349

349

Minimizing this a little bit 350

350

and so you see, now we get exactly the recipe 351

351

that we are clicking on here. 352

352

So watch what happens with the ID 353

353

when I click here on Pizza Casserole 354

354

or Casserole or whatever. 355

355

So it changed the ID up there 356

356

and changed the recipe here also in the view. 357

357

Great. 358

358

And now let's just fix this icon here 359

359

and actually, also here. 360

360

And then also all of these should not be highlighted. 361

361

We will take care of that a little bit later. 362

362

So we need to take away this class here of active. 363

363

And here we also need to take away this. 364

364

Okay? 365

365

And we will come back to this later again 366

366

when we actually start 367

367

to implement uploading our own recipes. 368

368

And here in the alt text, 369

369

we should just put that title as well. 370

370

Okay? 371

371

Now you see that actually the states 372

372

that we had here before in the page is gone 373

373

and so let's activate that hot module reloading 374

374

that I mentioned in the last section. 375

375

So remember that with parcel, we can do this. 376

376

So if module.hot, 377

377

then module.hot.accept. 378

378

All right? 379

379

And again, this is not real JavaScript, 380

380

at least this module.hot. 381

381

This is simply coming from parcel. 382

382

All right? 383

383

And now finally, let's also delete these fakes links 384

384

that we had before. 385

385

Let's reload. 386

386

And that looks a lot better. 387

387

Okay? 388

388

So let me now change something in the code. 389

389

For example, getting rid of this console.log here. 390

390

And so previously, that would then reload the entire page 391

391

but now, as we go back, 392

392

you see that the state here actually remains. 393

393

All right? 394

394

All it says is the console was cleared but that's it. 395

395

So the rest remains the same 396

396

and we can now also delete this user icon 397

397

from the recipeView. 398

398

So let's see where that is. 399

399

It is simply this div here. 400

400

And so once again, it will now not re-render everything. 401

401

Well, maybe we should re-render. 402

402

And yeah, now it's gone. 403

403

Well, it also messed up our button here for some reason. 404

404

So maybe that was not intended. 405

405

Maybe I should just remove this here. 406

406

So basically keeping an empty div. 407

407

Okay, so for the time being, 408

408

let's just leave it like this. 409

409

Okay. 410

410

Now, let's just see what happens when we search something 411

411

that for sure does not exist. 412

412

So you see that here we still get a success. 413

413

You see. 414

414

So we still get that data but the only difference 415

415

is that the recipes array is now empty 416

416

and here we also see that the array is empty coming 417

417

from the state. 418

418

So in this case, we actually want 419

419

to render like an error message here saying 420

420

that there was no result for that query. 421

421

So let's start by creating also 422

422

the errorMessage property here. 423

423

So let's copy these two actually to our resultsView. 424

424

And here let's say no recipes found for your query! 425

425

Please try again. 426

426

But now, how exactly 427

427

will we actually display this errorMessage 428

428

on the parentElement? 429

429

So we could do that right here in generateMarkup 430

430

and basically check if the array is empty 431

431

and if it is so, 432

432

then render the errorMessage. 433

433

So that would work. 434

434

However, we can also do that directly 435

435

in the render method. 436

436

So automatically, right as we receive the data. 437

437

And I believe that is what makes more sense. 438

438

So right in the beginning 439

439

when the render method is first called 440

440

and receives the data for the first time, 441

441

we can immediately check if that data actually exists. 442

442

So right now, we only simply assumed 443

443

that there always is data 444

444

and that we can then generate some markup with that data. 445

445

But as always, it's a good idea 446

446

to check if the data actually exists. 447

447

And that is true no matter if we receive a simple object 448

448

or if we receive an entire array of objects, 449

449

which is the case of the results. 450

450

So let's add a guard clause here. 451

451

So if there is no data, 452

452

then we want to return immediately 453

453

and we also want to render the error. 454

454

So we can do that all in one line 455

455

and this will then still work. 456

456

So this.renderError 457

457

and we actually don't even have to pass in any message 458

458

because we already automatically get the message 459

459

from this._errorMessage. 460

460

And so in this case, that is going to be this one 461

461

that we just specified before. 462

462

Right? 463

463

Now, however, in this case, 464

464

this check is actually not enough 465

465

because in fact, we do get data. 466

466

It's just an empty array 467

467

and so in this case, 468

468

we also want to treat the empty array 469

469

as though we had no data. 470

470

So this here basically only works for undefined 471

471

or for null. 472

472

But now we also want to check if the received data 473

473

is an array and if it is empty. 474

474

So we can do that by saying 475

475

so if there is no data or 476

476

and then basically, if the data is an array 477

477

and if it's empty. 478

478

And we can do that 479

479

by using a helper function 480

480

that is on the Array constructor, 481

481

which is isArray. 482

482

So we can check that. 483

483

And so if it's an array 484

484

and the length of the array is zero basically, 485

485

data.length zero, 486

486

well, then in this case, 487

487

exit this function immediately 488

488

and also render the error, okay? 489

489

So again, if there is no data 490

490

or if there is data, 491

491

but that data is an array, 492

492

and it is empty. 493

493

So in both these cases, we want the error to be shown. 494

494

So let's check that. 495

495

So with pizza, it all works the same 496

496

because there are results. 497

497

But now with this, ha, there are no results 498

498

and then we get our error message. 499

499

So great. 500

500

That works. 501

501

And so I think we are done actually with this part. 502

502

So just one more look at our flowchart. 503

503

So we implemented the event 504

504

that the user searches. 505

505

We asynchronously loaded the search results 506

506

and then we also rendered them to our user interface. 507

507

And so with that, we are done. 508

508

Right? 509

509

Just a final look here at the controller 510

510

that everything looks good. 511

511

So in the next lecture, we will actually take care 512

512

of the problem that we have these 59 results, 513

513

all one after another here. 514

514

So that's not good 515

515

and so we will implement pagination 516

516

in the next two lectures.

Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.