1.4 Routing, plugins and computed properties - VVJS/intro GitHub Wiki
You know the drill! If you've run into any problem so far, run the following in your terminal:
git checkout 1.4 --force
Now that we have a list of places, let's make a new page to show a bit of info about the place. We're going to make use of the Vue Router to do this. You can find the Vue router documentation here. First let's create a new component in the /src/views/
folder. Let's call it Place.vue. Now if you have vetur installed you can scaffold an empty component, otherwise just copy pasta this in:
<template>
<div>
This is the place page
</div>
</template>
<script>
export default {}
</script>
<style>
</style>
*One thing to note here, there has to be exactly one element inside of the template tags, you cannot have two siblings, or enter text directly.
Once we save this component, you may notice that yarn did not automagically rebuild for us. That's because we have to import it into our project first. Head over to router.js in the src folder and import it:
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Place from './views/Place.vue'
Now we will start by copying the home route, but this time we want a dynamic segment. A dynamic route segment is denoted by a colon (in this case, uuid
is the dynamic part). You can learn more about it here.
We are also going to add a property for props. This will directly inject the dynamic segment into our Place.vue view component as a prop. You can learn more about this here.
{
path: '/',
name: 'home',
component: Home
},
{
path: '/places/:uuid',
name: 'place',
component: Place,
props: true
}
Now let's go back to ListItemPlace.vue and add a to
attribute to the v-list-tile
element. We have two options of passing the link, we can add the link directly using a template string like so:
<v-list-tile avatar
:to="`/places/${place.properties.uuid}`">
Or you can link to a named route like so
<v-list-tile avatar
:to="{ name: 'place', params: { uuid: place.properties.uuid } }">
*Note that if we were binding a variable to the route, we could simply type to="/about"
(without the colon), for example.
Now save the project and click one of the places on your list page in the browser, and you should see a pretty amazing place page:
Now, back to the Place.vue file, we will grab the uuid as a prop and use it to make another API call to the sport places API. Replace your script tag with this:
<script>
import axios from 'axios'
export default {
props: ['uuid'],
data() {
return {
place: null
}
},
async mounted() {
const { data } = await axios.get(`https://sportplaces-api.herokuapp.com/api/v1/places/${this.uuid}`)
this.place = data
console.log(data)
}
}
</script>
Now save and refresh. Now in your console (F12
) you should see the data returned from the sport places API about this place. Now let's display this data. You can play around with displaying whichever data you like in your template, however if you are lazy just copy and replace your template tags with this code.
<template>
<v-layout class="pt-4" column align-center>
<v-card>
<v-card-media :src="getPhotoUrl(place)" height="200px">
</v-card-media>
<v-card-title primary-title>
<div>
<h3 class="headline mb-0">{{ place.properties.name }}</h3>
<div>{{ place.properties.address_components.address }}</div>
<div>
Suggested By:
<span>{{ place.properties.user.first_name }}</span>
<span>{{ place.properties.user.last_name }}</span>
</div>
</div>
</v-card-title>
</v-card>
</v-layout>
</template>
Once you save you will see a couple of errors in the console.
-
For all of the properties, since
place
isn't available when the page loads, we have to splash in a littlev-if="place"
on thev-card
element:<v-card v-if="place">
. -
getPhotoUrl
is not defined again (classicgetPhotoUrl
). Instead of adding it here and duplicating our code from before, let's add a plugin so we can access this method from any component!
There are a few different things that a plugin can be used for, you can check out the full list here. We will be focusing on adding a method which will globally be available in our templates.
Create a new file in the src/plugins/
folder called photo.js, and cut the getPhotoUrl
method out of the ListItemPlace.vue file. We are going to make some minor tweaks to it, like adding an optional max width parameter.
import Vue from 'vue'
Vue.use({
install(_vue) {
_vue.prototype.$getPhotoUrl = function(place) {
return `https://s3-us-west-2.amazonaws.com/meetups.hc/VVJS/intro/${place.properties.google_place_id}.jpg`
}
}
})
We'll also have to install this plugin. open up main.js from the /src/
and add import './plugins/photo'
to the file like so:
import '@babel/polyfill'
import Vue from 'vue'
import './plugins/vuetify'
import './plugins/photo'
...
We will now have the $getPhotoUrl
method available globally. Go and change the templates of ListItemPlace.vue and Place.vue to use this new method instead.
<!-- ListItemPlace.vue -->
<img :src="$getPhotoUrl(place)">
<!-- Place.vue -->
<v-card-media :src="$getPhotoUrl(place)" height="200px">
</v-card-media>
And finally import our new plugin into our main.js file.
import './plugins/photo.js'
Now we can remove the getPhotoUrl
method from ListItemPlace.vue since we don't need it any more.
Computed properties are good for doing some complicated logic in your templates. Vue will actually watch the values inside the method for changes, if something changes it will automatically update the results of the method. You can find more information on computed properties here. For our example, we will take this from Place.vue:
<div>
Suggested By:
<span>{{ place.properties.user.first_name }}</span>
<span>{{ place.properties.user.last_name }}</span>
</div>
And turn it into this, it looks a lot cleaner:
<div>
{{ suggested }}
</div>
And add a computed property to your component
...
async mounted() {
const { data } = await axios.get(`https://sportplaces-api.herokuapp.com/api/v1/places/${this.uuid}`)
this.place = data
},
computed: {
suggested() {
const user = this.place.properties.user
return `Suggested by: ${user.first_name} ${user.last_name}`
}
}
Now save and refresh!
That concludes this tutorial, you can checkout the final tag here:
git checkout 1.f --force
Feel free to mess around with the code as you please.