gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
In the last tutorial, we created a title
component, which we're reusing so that we can have a consistent look and styling.
<template> | |
<div :class="$style.component"> | |
<h1> | |
{{ categoryName }} | |
</h1> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: 'Title', | |
... lines 12 - 32 | |
}; | |
</script> | |
<style lang="scss" module> | |
.component { | |
h1 { | |
font-size: 1.7rem; | |
} | |
} | |
</style> |
Cool! In product-show.vue
, let's use that! Import TitleComponent
from @/components/title
, add this into the components
key, then up here, instead of our manual <h1>
, say <title-component />
.
<template> | |
<div> | |
<loading v-if="loading" /> | |
<div v-if="product"> | |
<title-component /> | |
</div> | |
</div> | |
</template> | |
<script> | |
... lines 12 - 13 | |
import TitleComponent from '@/components/title'; | |
... line 15 | |
export default { | |
... line 17 | |
components: { | |
Loading, | |
TitleComponent, | |
}, | |
... lines 22 - 40 | |
}; | |
</script> |
I'm purposely not passing a prop to this yet... and yes, I know it looks weird - like "how will it know what title to render?". Ya see... we have a problem.
Back at the browser, we're on a product page and it... seems to... kind of work. It says "All Products". But more importantly, there's an error!
Missing required prop
categories
.
We're apparently supposed to pass a categories
prop
to title... which is weird, because I'm not sure what categories
have to do with printing a title. We better go check out that component. Ah... this component is way too smart: it expects us to pass it the array of all categories
and the currentCategoryId
. And then it does the logic to figure out if we're on a category page and either prints that category name or "All Products". There's no way for us to make it render anything else.
<template> | |
<div :class="$style.component"> | |
<h1> | |
{{ categoryName }} | |
</h1> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: 'Title', | |
props: { | |
currentCategoryId: { | |
type: String, | |
default: null, | |
}, | |
categories: { | |
type: Array, | |
required: true, | |
}, | |
}, | |
computed: { | |
categoryName() { | |
if (this.currentCategoryId === null) { | |
return 'All Products'; | |
} | |
const category = this.categories.find((cat) => (cat['@id'] === this.currentCategoryId)); | |
return category ? category.name : ''; | |
}, | |
}, | |
}; | |
</script> | |
... lines 35 - 43 |
What we need to do is convert title
into a dumb component that does nothing more than receives props and uses them. This is really a mistake that I made in the last tutorial. We've talked a few times about having dumb components that mostly just render markup and then smart components that do calculations & load data, but don't render much markup. This is not an absolute rule... and I don't always follow it - but it's a nice guide to keep things organized and reusable.
Ok: let's make this component less smart! Under props
, we only need one: call it text
. It will be a String
and also required.
... lines 1 - 8 | |
<script> | |
export default { | |
name: 'Title', | |
props: { | |
text: { | |
type: String, | |
required: true, | |
}, | |
}, | |
... lines 18 - 28 | |
}; | |
</script> | |
... lines 31 - 39 |
Then, in the template, instead of categoryName
, just render text
!
<template> | |
<div :class="$style.component"> | |
<h1> | |
{{ text }} | |
</h1> | |
</div> | |
</template> | |
... lines 8 - 39 |
What about all the logic inside the categoryName
computed prop? Copy this and delete the entire computed
section. Now open assets/components/catalog.vue
. This is the one place that currently renders the title
component and it is what should be responsible for determining its title text. Down in the component, this doesn't have a computed
section yet, so add one after data
- computed
- and paste categoryName
. Both this.currentCategoryId
and this.categories
are available on this component, so this "should" just work.
... lines 1 - 32 | |
export default { | |
name: 'Catalog', | |
... lines 35 - 58 | |
computed: { | |
categoryName() { | |
if (this.currentCategoryId === null) { | |
return 'All Products'; | |
} | |
const category = this.categories.find((cat) => (cat['@id'] === this.currentCategoryId)); | |
return category ? category.name : ''; | |
}, | |
}, | |
... lines 70 - 105 | |
}; | |
</script> |
Back up top, we can shorten <title-component>
significantly: we only need to pass text
set to categoryName
.
<template> | |
<div> | |
<div class="row"> | |
<div class="col-3"> | |
<title-component :text="categoryName" /> | |
</div> | |
... lines 7 - 9 | |
</div> | |
... lines 11 - 19 | |
</div> | |
</template> | |
... lines 22 - 105 |
Let's make sure this still works. Back at the browser, click "All Products". The title looks good! Try "Office Supplies" and... perfect!
Thanks to this, in product-show
, we're free to pass whatever we want to the title, like :text="product.name"
.
<template> | |
<div> | |
<loading v-if="loading" /> | |
<div v-if="product"> | |
<title-component :text="product.name" /> | |
</div> | |
</div> | |
</template> | |
... lines 10 - 43 |
I love that. And... it even works.
Next: let's bring this page completely to life with a full template and a nice, standalone color selector that we'll soon use to selected a product color before adding it to the cart.
"Houston: no signs of life"
Start the conversation!
// package.json
{
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.15.1", // 5.15.1
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.3
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.2.0
"eslint-plugin-import": "^2.19.1", // 2.22.1
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.7
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.12
"vue-loader": "^15.9.1", // 15.9.4
"vue-template-compiler": "^2.6.11", // 2.6.12
"webpack-notifier": "^1.6.0" // 1.8.0
}
}