If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOk: we have products
and searchTerm
data. Let's update the searchTerm
when the search-bar
component tells us it's changed.
search-products
Event in CatalogRemember, in that component, we're dispatching an event called search-products
. In Catalog
, up in the template, find the <search-bar
element and add @search-products="onSearchProducts"
, which is a method that we now need to create.
<template> | |
... lines 2 - 9 | |
<div class="col-9"> | |
<search-bar @search-products="onSearchProducts" /> | |
</div> | |
... lines 13 - 23 | |
</template> | |
... lines 25 - 82 |
Down in the code, do it: add methods: {}
and then onSearchProducts()
. Since this method is going to be called when an event is emitted, it will receive an event
argument. And because, when we emitted the event, we added a term
key, we can use that here! We can say this.searchTerm = event.term
.
... lines 1 - 25 | |
<script> | |
... lines 27 - 32 | |
export default { | |
... lines 34 - 74 | |
methods: { | |
onSearchProducts(event) { | |
this.searchTerm = event.term; | |
}, | |
}, | |
}; | |
</script> |
Let's go check it out! Back on the dev tools... if I type disc
, the searchTerm
in SearchBar
, of course, updates. But if we look in Catalog
, the search term also changed here! Yes!
We can finally filter the product list. Scroll up to the template. To render the products, we pass them into the <product-list>
component: we're currently passing in all of the products. But when there is a searchTerm
we now want this to be a subset.
This is, yet again, a situation where we need to reference a value in the template that requires some custom logic. In other words, it's computed property time! In preparation, pass filteredProducts
to product-list
.
<template> | |
<div> | |
... lines 3 - 14 | |
<product-list | |
:products="filteredProducts" | |
... line 17 | |
/> | |
... lines 19 - 22 | |
</div> | |
</template> | |
... lines 25 - 93 |
Copy that name, go down and, above created
, add computed
with filteredProducts()
. Inside the function, if (!this.searchTerm)
, then we can just return this.products
: the normal array of products.
... lines 1 - 32 | |
export default { | |
... lines 34 - 58 | |
computed: { | |
filteredProducts() { | |
if (!this.searchTerm) { | |
return this.products; | |
} | |
... lines 64 - 67 | |
}, | |
}, | |
... lines 70 - 90 | |
}; | |
... lines 92 - 93 |
But if there is a search term, return this.products.filter()
and pass an arrow function with a product
argument. I'm going to use the super hipster shortcut syntax: because I don't have any curly braces - just parentheses - this has an implied return
statement. So, return product.name.toLowerCase().includes(this.searchTerm.toLowerCase())
.
... lines 1 - 58 | |
computed: { | |
... lines 60 - 64 | |
return this.products.filter((product) => ( | |
product.name.toLowerCase().includes(this.searchTerm.toLowerCase()) | |
)); | |
}, | |
}, | |
... lines 70 - 93 |
Basically, loop over all the products and return a new array containing only the products whose name includes the search term.
Let's try it! Over in the browser, this is the full list of office supplies. If I type in disk
... yes! It shows just one! Try dis
... 2!
But... as cool and fast as this is... our JavaScript filtering has some serious downsides. First, if our products were paginated, this would not work: the user would only be searching through a single page of products! Yikes! And second, what if we wanted the search to also match on fields that are not shown in this list? Or maybe we have a super-cool Elasticsearch system that we want to use?
The point is: filtering on the client-side might work in some simple cases... but most of the time, you'll probably want to perform a search on the server via an Ajax call. Let's do that next!
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.0
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.1.0
"eslint-plugin-import": "^2.19.1", // 2.20.2
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.5
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.11
"vue-loader": "^15.9.1", // 15.9.2
"vue-template-compiler": "^2.6.11", // 2.6.11
"webpack-notifier": "^1.6.0" // 1.8.0
}
}
Hi! there is a typo in a challenge:
I LOVE hamsters. In fact, I love them so much that I wronte