All language subtitles for 12. Implementing Search Results - Part 1

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 start implementing the next feature 2

2

of our application, 3

3

which is going to be the search functionality. 4

4

And let's start by taking a look and or flowchart here. 5

5

And so, again, 6

6

we already have this part here basically now implemented, 7

7

and now, we are going to work basically first on this part. 8

8

So handling the event of a user 9

9

searching for recipes, 10

10

then loading the search results and rendering them. 11

11

So that's going to be this lecture and the next one. 12

12

And then afterwards, 13

13

we are going to worry about the pagination. 14

14

So again, we will now focus on these three parts. 15

15

And so for that, 16

16

we need to now implement the model, the view 17

17

and the controller that binds everything together. 18

18

And usually, I find it easiest to start with the data. 19

19

So basically with the model, 20

20

which means in this case, 21

21

starting to make some API calls 22

22

in order to load some search results. 23

23

And then, once we have that part working, 24

24

we can then render them on the screen 25

25

and also care about the actual event. 26

26

Okay, so let's actually leave that open here at the end 27

27

and go to our model here, 28

28

and start implementing the search functionality. 29

29

So, just like before, 30

30

we are going to create a function 31

31

that will be exported 32

32

so that it can be used 33

33

by the controller. 34

34

And this one, 35

35

I'm gonna call it loadSearchResults. 36

36

And so, since this one will be performing AJAX calls 37

37

it's going to be an async function. 38

38

Now, again dysfunction here 39

39

is going to be called by the controller. 40

40

And so, it's going to be the controller 41

41

who will tell this function 42

42

what it would actually search for. 43

43

So basically, it will pass in a query 44

44

like string, which we can then 45

45

pluck into our API call, now, right? 46

46

And here we are going to need a try catch block, 47

47

and here in the catch block, 48

48

all we will do is to, 49

49

basically do the same as here. 50

50

So, all we're really interested in here 51

51

is to throw the error again 52

52

so that eventually, 53

53

we will be able to use it in the controller. 54

54

So just like before 55

55

in the last lecture, 56

56

where we threw with the error here again. 57

57

So that part is easy, 58

58

but now let's actually implement the functionality. 59

59

And to do that, 60

60

let's go back to our documentations page. 61

61

And so, this is how we get all recipes. 62

62

So making a get request to this path, 63

63

and then, with the search parameter, 64

64

and the way we add a parameter, 65

65

and I think I explained this before 66

66

is with the question mark, 67

67

and then search equal, 68

68

and then, pizza here in our case 69

69

is actually the search query. 70

70

And again, for now, 71

71

don't worry about the key. 72

72

And we can actually already see 73

73

what the results will look like here for pizza. 74

74

And so, basically, 75

75

this is the URL 76

76

that we need to call in our AJAX request. 77

77

So let me actually copy it 78

78

and let's go back. 79

79

And so now, 80

80

we can, just like before, 81

81

use the get JSON method. 82

82

And so, that will then fetch the data 83

83

and also convert it to JSON 84

84

and create an error if something went wrong. 85

85

So get JSON returns a promise. 86

86

And so we await that here 87

87

and store it into data, 88

88

just like always. 89

89

So get JSON 90

90

and then the URL, 91

91

and we need a template literal. 92

92

And so, yeah now we just have to replace everything 93

93

to make this work. 94

94

And the first thing 95

95

is to actually take this here again out, 96

96

and replace it with this API URL 97

97

that we already have in our configuration file, right? 98

98

So API URL, 99

99

and I think 100

100

that actually already includes the recipes. 101

101

Yup, so it's everything. 102

102

And usually, actually a URL ends with a slash, 103

103

so it should be like this. 104

104

And so here, let's take that out, 105

105

actually, and then here as well. 106

106

Then here, question mark search 107

107

and then this one is going to be our query. 108

108

Now, right? 109

109

And so, we can then 110

110

already log that data 111

111

to the console, 112

112

to take a look at it 113

113

before we then manipulate it a little bit. 114

114

And so right now, 115

115

this would already be working. 116

116

And so let's, 117

117

before we actually write any controller or any view, 118

118

or we can already call that function here. 119

119

So load search results, 120

120

and then let's try it, 121

121

has always with pizza 122

122

and see what we get. 123

123

So that's right here. 124

124

And indeed, this is the result that we get here. 125

125

So it's coming from model at line 35. 126

126

So that's where we were. 127

127

And so here, 128

128

is the data that we get back. 129

129

So we have an object 130

130

which has a data property, 131

131

which then has a recipe's property, 132

132

which is this array. 133

133

And then, each array contains 134

134

all of this data 135

135

about each of the recipes. 136

136

So, again, this object here is called data 137

137

then in there, there is data again, 138

138

and then in there, there is recipes, 139

139

which is then, 140

140

the array itself 141

141

where each of the elements 142

142

is an object 143

143

with only some of the data 144

144

about the recipe. 145

145

So you see, it's not the complete recipe object, 146

146

it's only some of the data 147

147

so that we can actually display it 148

148

then here in the search results. 149

149

So without the unnecessary data 150

150

like ingredients and all that. 151

151

All right, so let's now take this data 152

152

and store it into our state. 153

153

And also, we will want to change, 154

154

again, this one here, 155

155

so to image only. 156

156

And so, we will basically create some new objects 157

157

based on this data that we receive here. 158

158

All right. 159

159

So, we get data.data.recipes. 160

160

So this is the array. 161

161

So this is the array of all the objects. 162

162

And now we want to create a new array 163

163

which contains the new objects 164

164

where the property names are different. 165

165

So, let's map over this, 166

166

and each element 167

167

is going to be a recipe. 168

168

And then here, we will simply return a new object. 169

169

That's actually copied a code from here 170

170

because they are the same, 171

171

at least some of them. 172

172

So taking all this, 173

173

int here now, this is only called a rec. 174

174

Okay, and also we don't have the source URL, 175

175

we only have ID, title, publisher and image URL, okay. 176

176

So this will return a new array with the new objects. 177

177

And so now, 178

178

where should we store that? 179

179

Well, as you can guess, 180

180

we will put it also in our state. 181

181

So again, the state contains all the data that we need 182

182

in order to build our application. 183

183

So let's call this one search 184

184

and all the data 185

185

about the application 186

186

that I just mentioned 187

187

might as well 188

188

also include the search query itself. 189

189

So let's create a new object here 190

190

and then specify the query, 191

191

which we start as an empty string. 192

192

And then, the results, let's say, 193

193

results, and will start 194

194

as an empty array. 195

195

So, basically the state 196

196

should contain all the data 197

197

really about the application. 198

198

Now, in this case, 199

199

we might not even need the query for now, 200

200

but it's still a good idea 201

201

to already store it here in the state, 202

202

because maybe one day 203

203

we will need it. 204

204

And then the data's already there for us. 205

205

For example, we might want to add some analytics 206

206

in the future 207

207

to know which queries are made the most. 208

208

And so by then, 209

209

yeah, as I said, 210

210

that would become useful. 211

211

Okay. 212

212

But anyway, let's now store this data 213

213

in state.search.results, right. 214

214

And here at the beginning, 215

215

the very first thing 216

216

that we're going to do 217

217

is to state.search.query 218

218

equal to query. 219

219

All right. 220

220

And now, let's quickly 221

221

just to see if everything worked, 222

222

log data to the console. 223

223

So state.search.results. 224

224

And here we are. 225

225

So that is exactly the kind of array that we had before. 226

226

And now the image URL we had before 227

227

is indeed called image. 228

228

And so everything has the same format as before. 229

229

So, we needed to do that 230

230

because here the image is also called image. 231

231

And of course, we want everything to have the same names 232

232

throughout the entire application, all right. 233

233

So let's get rid of this 234

234

because of course, 235

235

we want to call this function in a controller. 236

236

And so let's go there 237

237

to the controller 238

238

and basically create a new function 239

239

which is going to be like the new controller. 240

240

So const controlSearchResults. 241

241

And so this one 242

242

we'll call the asynchronous function loadSearchResults. 243

243

And so this one, of course 244

244

then also need to be an asynchronous function itself. 245

245

And so, as always try catch, 246

246

and here for now, let's simply log the error 247

247

and we will then fix that later. 248

248

So, here is where we actually 249

249

will want to call the loadSearchResults that we just built. 250

250

So that is in model.loadSearchResults. 251

251

And here we then, 252

252

we'll need to pass in the query, 253

253

but for now, let's just do that again manually. 254

254

And of course, 255

255

we need to await this, 256

256

but we do not store any results anywhere 257

257

because, just like the loadRecipe function, 258

258

this one also doesn't return anything. 259

259

All it does 260

260

is to manipulate the state. 261

261

And so, then we should be able to do this console.log 262

262

in the controller 263

263

and still get access to the results, right? 264

264

So, let's see. 265

265

Now, of course, we first have to also call this function. 266

266

And again, later, 267

267

we will, of course hook this us up to an event list 268

268

and our material, let's just 269

269

call it right away. 270

270

And now we get status not defined, all right. 271

271

And that is because, 272

272

of course it needs to be model.state.search.results. 273

273

So you see that this is becoming a pretty long chain here 274

274

but nevermind, that's not a problem at all, 275

275

because we know exactly what all of this is. 276

276

And so, now indeed 277

277

we get back our 59 search results for pizza. 278

278

But now, instead of only searching for pizza, 279

279

we actually want to get the query right here 280

280

from this input field, right? 281

281

And we also want to start this whole process 282

282

of loading the search results. 283

283

So we only want that to happen 284

284

when this button here is clicked. 285

285

And so, now let's basically create a view 286

286

only for this search part here. 287

287

So right here, 288

288

we will have a view 289

289

for this year. 290

290

So for the search field, 291

291

and for the button, 292

292

and then a different view 293

293

which will actually render the results. 294

294

So, it's a good idea 295

295

to keep every view really focused. 296

296

And so, it's best 297

297

to just do one for this part, 298

298

and then one for displaying the results, 299

299

also because in the user interface, 300

300

they're actually in kind of different places also. 301

301

So it makes sense to have a different view. 302

302

Now this view here 303

303

is of course 304

304

not going to render anything, 305

305

but what it will do 306

306

is to basically give us the content 307

307

of this input field. 308

308

So getting that input data 309

309

is of course 310

310

something that has to do with a DOM. 311

311

And so, it should be in a view 312

312

and not in a controller, right? 313

313

So of course, 314

314

if we wanted to be lazy, 315

315

we could go ahead 316

316

and select the element that we want. 317

317

So it doesn't matter. 318

318

And then from there, 319

319

we would simply get the value 320

320

and then use that as our query. 321

321

So again, we could do that here, 322

322

but this is clearly about the DOM. 323

323

And so, in order to follow our architecture, 324

324

we will create a new view right now. 325

325

And this one is going to be called the searchView.js. 326

326

And just like before, 327

327

here, we will create a class called searchView 328

328

and we will then not export that class 329

329

but export an instance, 330

330

so an object that was created by this class. 331

331

So export default new SearchView, 332

332

and without passing in any data, 333

333

done just like before, 334

334

we will have a parent element. 335

335

So just like in the recipe view, 336

336

so a parent element, 337

337

and then we will set that to something, 338

338

query selector, and now let's see what we get 339

339

here in the DOM. 340

340

So in the HTML, 341

341

so the search, 342

342

now, it's this one. 343

343

So we have this entire form, 344

344

which is called search 345

345

and which has this input field here 346

346

and also the button. 347

347

And so I think that this is the element 348

348

that makes sense to select. 349

349

So the one with the class of search, so .search. 350

350

So this is our parent element here in this case. 351

351

Now, again, this class is not going to render anything. 352

352

All we want is to get the query 353

353

and eventually to also listen for the click event 354

354

on the button, 355

355

but let's start with the query here. 356

356

And so, let's create a method 357

357

that we will then call from the controller called getQuery. 358

358

And all this will do 359

359

is to return this.#parentElement. 360

360

And so again, 361

361

that's going to be the search. 362

362

And then from there, 363

363

we want to select this input field. 364

364

So this one with this class. 365

365

And so let's a select this child element 366

366

using a querySelector, 367

367

and then simply get the value of that. 368

368

Okay, and that's actually it. 369

369

And again, of course 370

370

we could have written this exact same code 371

371

in a controller, 372

372

but that wouldn't make any sense, 373

373

because this is not concerned about the DOM at all. 374

374

So we don't want to have any DOM elements in here. 375

375

We don't even want to know what the DOM looks like. 376

376

So actually here we have this, 377

377

but we don't want this here. 378

378

Let's get rid of all this clutter here actually. 379

379

And now, I want to 380

380

get the searchView here. 381

381

And then here, 382

382

we can get that query 383

383

by saying searchView.getQuery. 384

384

And of course, 385

385

there might be no query. 386

386

And so, let's add another guard clause here. 387

387

So if there is no query, 388

388

then return immediately. 389

389

And so here, 390

390

we will now no longer look for pizza, 391

391

but for query. 392

392

Now, if we run this, 393

393

then of course there will be no result 394

394

because, well, right now, 395

395

there is nothing here to be found. 396

396

So that controller function 397

397

runs right in the beginning 398

398

when the application actually loads. 399

399

And so by then of course, 400

400

there is a no value here. 401

401

And so, in order to actually make this work, 402

402

we now need to listen for the event 403

403

of basically clicking this button or submitting this form. 404

404

And then, only on that event, 405

405

we want to actually call, 406

406

this controller function here. 407

407

So not in the beginning when the script loads. 408

408

So, in order to do that, 409

409

we will once again, 410

410

use the publisher subscriber pattern. 411

411

So basically exactly what we did here, right? 412

412

So we will list in for the event 413

413

in the view right here, 414

414

and then pass the controller function. 415

415

So the handler function 416

416

into the method that we will build here. 417

417

So this addHandler, a search method here 418

418

is basically going 419

419

to be the publisher anti-control search results function 420

420

is going to be the subscriber. 421

421

Okay, so hopefully you really understood that pattern 422

422

that we used before. 423

423

And so this now, 424

424

it should be obvious. 425

425

So, let's take our parent element. 426

426

So this.#parentElement of course, 427

427

and then this is where 428

428

we will actually add the event listener. 429

429

So not to the button, 430

430

but really to the entire form 431

431

because there, we can listen for the submit event. 432

432

And so then, this will work 433

433

no matter if the user clicks the submit button 434

434

or if the user hits Enter while typing the query. 435

435

Now here, we cannot simply call the handler immediately, 436

436

because remember, as we did many times before 437

437

when we submit a form, 438

438

we need to first prevent the default action, 439

439

because otherwise the page is going to reload. 440

440

So, preventDefault. 441

441

And only after that, 442

442

we can call the handler function. 443

443

And, as you already know, 444

444

this handler function 445

445

should be the control searchResults function. 446

446

And so, all we have to do now 447

447

is to call this method 448

448

and pass in that function. 449

449

So, let's do that here right at the beginning. 450

450

So searchView.addHandlerSearch. 451

451

So you'll see that I'm always going to use 452

452

this name here of addHandler, 453

453

and then we pass in the controller function 454

454

and that's it. 455

455

So now it should actually already work. 456

456

So let's see. 457

457

And actually, let's clear up all this clutter 458

458

here a little bit. 459

459

Okay, so this console.log, 460

460

and there's also some here in the recipe view. 461

461

So that's this one. 462

462

Okay, so that's again, try pizza 463

463

and yeah, beautiful, it worked. 464

464

So we get 465

465

this data first here coming from the model, 466

466

and then also in a controller, 467

467

we also logged it. 468

468

And so here we have the exact same 59 data 469

469

that we had before. 470

470

Let's try something else now, 471

471

avocado, let's say, 472

472

so I hit Enter, 473

473

and, so this time we got 39 search results 474

474

and you see, 475

475

all of them basically have avocado 476

476

right there in the title, 477

477

it's really beautiful 478

478

that it already works this great. 479

479

Now just one small detail, 480

480

is that, after we search, 481

481

we should probably clear out this field. 482

482

So let's add another small method for that in the view. 483

483

So, and this one here, 484

484

so clearInput, 485

485

and once again, 486

486

having it nicely encapsulated inside of the searchView. 487

487

So again, this could simply be also in a controller, 488

488

because, it's really just one line of code, 489

489

but we want to keep everything separated. 490

490

This will make it so much easier to add features 491

491

in the future. 492

492

And it's really so much better. 493

493

So, all we do is to set this to empty and that's it. 494

494

All right, let's try it one more time. 495

495

Let's say pasta this time. 496

496

Ah, of course we never called DOM method here anywhere. 497

497

So we need to do that in the controller. 498

498

And let's actually add some more comments here. 499

499

So Get search query. 500

500

And the code itself is actually pretty self explanatory. 501

501

And so many developers will tell you 502

502

you should not comment it, 503

503

but I think 504

504

that this is actually very helpful when you read the code 505

505

in like one or two years from now. 506

506

So, I would advise you to always write comments like this 507

507

even if your code seems pretty obvious, 508

508

especially when it's like 509

509

a bigger list of instructions like this, 510

510

so Render results. 511

511

So right now our rendering is only a console.log. 512

512

But here, when we get a search query, 513

513

we can actually then 514

514

immediately also clear it afterwards. 515

515

Or in fact, 516

516

in order to keep this controller even simpler, 517

517

we can do that 518

518

right in the getQuery method. 519

519

So, let's go back here, 520

520

and now we can make this private, 521

521

so we're not going to use it outside. 522

522

And then let's actually call it here. 523

523

So this.#clearInput. 524

524

And then of course, 525

525

we first need to store this somewhere here. 526

526

So we get the query, 527

527

then we clear the field 528

528

and then we return the query. 529

529

All right, so that should now work. 530

530

So pasta and clears the field, 531

531

and gives us or 45 results down here about pasta. 532

532

Great, so that works just fine. 533

533

And so, all there's left to do 534

534

is to now implement actually the view. 535

535

So the second view basically. 536

536

So the one 537

537

that is responsible 538

538

for then rendering all the results 539

539

here in this sidebar. 540

540

And so that's going to be a little bit of work. 541

541

So let's leave that for the next video.

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