v-else
A common pattern when showing or hiding elements is to instead show a different piece of content. Whilst we could usev-iforv-showmultiple times, we also have access to thev-elsedirective, which can be used directly after showing or hiding the element.
Let's take a look at this in more detail:
<
article v-if="admin"
>
<
header
>
Protected Content
<
/header
>
<
section class="main"
>
<
h1
>
If you can see this, you're an admin!
<
/h1
>
<
/section
>
<
/article
>
<
article v-else
>
<
header
>
You're not an admin!
<
/header
>
<
section class="main"
>
<
h1
>
Perhaps you shouldn't be here.
<
/h1
>
<
/section
>
<
/article
>
By adding thev-elsedirective to the second<article>, we're telling Vue that we want to show this DOM element whenever the first condition is hidden. Because of the way this works, we don't have to pass a value tov-elseas Vue is specifically looking for a structural directive in the preceding element.
It's important to realize that this wouldn't work if we had an element in between thev-ifandv-elsedirective(s), such as this:
<
article v-if="admin"
>
<
header
>
Protected Content
<
/header
>
<
section class="main"
>
<
h1
>
If you can see this, you're an admin!
<
/h1
>
<
/section
>
<
/article
>
<
h1
>
The v-else will be ignored.
<
/h1
>
<
article v-else
>
<
header
>
You're not an admin!
<
/header
>
<
section class="main"
>
<
h1
>
Perhaps you shouldn't be here.
<
/h1
>
<
/section
>
<
/article
>
v-else-if
Whilstv-elseworks well in standardIF NOT AthenBscenarios, you may want to test for multiple values and show a different template. Similar tov-else, we can usev-else-ifto change the behavior of our application. For this example, we'll have fun by using a generator as introduced with ES2015.
To use the generator, we'll need to install thebabel-polyfillpackage; this also allows us to use things such asasyncandawaitbetter promise handling:
$ npm install babel-polyfill --save-dev
After installing it, we can modify our Webpack configuration (webpack.config.js) to include it inside of our entry files:
module.exports = {
entry: ['babel-polyfill', './src/main.js'],
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js',
},
// Omitted
If we hadn't installed the appropriate polyfill, we'd not be able to use the generator functionality within our project. Let's make a new method namedreturnRole()that gives us one of three users "roles" when called:
export default {
name: 'app',
data() {
return {
role: '',
}
},
methods: {
*returnRole() {
yield 'guest';
yield 'user';
yield 'admin';
}
}
};
If you've never seen a generator function before, you may be wondering what the asterisk (*) is that we've prefixed to our function name, as well as theyieldkeyword. This essentially allows us to step through the function by capturing an instance of it. For example, let's make a data value that returns our iterator, which we can callnext()on:
data() {
return {
role: '',
roleList: this.returnRole()
}
},
methods: {
getRole() {
/**
* Calling this.roleList.next() gives us an Iterator object with the interface of:
* { value: string, done: boolean}
* We can therefore check to see whether this was the
>
last
<
yielded value with done, or get the result by calling .value
*/
this.role = this.roleList.next().value;
},
We can, therefore, make a template that takes advantage ofv-if-elseby displaying different messages depending on the user role:
<
template
>
<
div id="app"
>
<
article v-if="role === 'admin'"
>
<
header
>
You're an admin!
<
/header
>
<
section class="main"
>
<
h1
>
If you can see this, you're an admin!
<
/h1
>
<
/section
>
<
/article
>
<
article v-else-if="role === 'user'"
>
<
header
>
You're a user!
<
/header
>
<
section class="main"
>
<
h1
>
Enjoy your stay!
<
/h1
>
<
/section
>
<
/article
>
<
article v-else-if="role === 'guest'"
>
<
header
>
You're a guest!
<
/header
>
<
section class="main"
>
<
h1
>
Maybe you should make an account.
<
/h1
>
<
/section
>
<
/article
>
<
h1 v-else
>
You have no role!
<
/h1
>
<
button @click="getRole()"
>
Switch Role
<
/button
>
<
/div
>
<
/template
>
There are different messages shown on the screen depending on the user role. If the user has no role, we usev-elseto show a message statingYou have no role!. This example shows how we can take advantage of structural directives to truly change the DOM depending on our application state.
Filters
In this section, we're going to investigate filters; you may have come across filters before in frameworks such as Angular (Pipes). Perhaps we want to create a filter that allows us to format a date in a readable format (DD/MM/YYYY). Let's create a playground project to investigate this further:
# Create a new Vue project
$ vue init webpack-simple vue-filters
# Navigate to directory
$ cd vue-filters
# Install dependencies
$ npm install
# Run application
$ npm run dev
If we had some test people and used thev-fordirective to display them on screen, we'd get the following result:
To obtain the result shown in the preceding screenshot, where we display our test people with the appropriate data through thev-fordirective, we would have to add the following code:
<
template
>
<
div id="app"
>
<
ul
>
<
li v-for="person in people" v-bind:key="person.id"
>
{{person.name}} {{person.dob}}
<
/li
>
<
/ul
>
<
/div
>
<
/template
>
<
script
>
export default {
name: 'app',
data() {
return {
people: [
{
id: 1,
name: 'Paul',
dob: new Date(2000, 5, 29),
},
{
id: 2,
name: 'Terry',
dob: new Date(1994, 10, 25),
},
{
id: 3,
name: 'Alex',
dob: new Date(1973, 4, 15),
},
{
id: 4,
name: 'Deborah',
dob: new Date(1954, 2, 5),
},
],
};
},
};
<
/script
>
We could do the work of converting the date ourselves, but where possible it's always worth looking to see if there is a trusted third-party component that can do the same thing. We'll be using moment (https://momentjs.com) to do this.
Let's installmomentfor our project:
$ npm install moment --save
We can then add it to ourApp.vue:
<
script
>
import moment from 'moment';
export default {
// Omitted
}
<
/script
>
Locally registered filters
We then have a choice: add the filter locally to this Vue instance, or add it globally to the entire project. We'll first look at how to add it locally:
First, we'll create a function that takes in a value and returns the date as a formatted date usingmoment:
const convertDateToString = value =
>
moment(String(value)).format('MM/DD/YYYY');
We can then add a filters object to our Vue instance and reference this by akey, such asdate. When we call thedatefilter inside of our template, the value will be passed to this filter and instead, we'll display the converted date on screen. This can be done by using the|key, as seen in the following code:
<
ul
>
<
li v-for="person in people" v-bind:key="person.id"
>
{{person.name}} {{person.dob | date}}
<
/li
>
<
/ul
>
Finally, to add this to the local Vue instance, we can add afiltersobject that references our function:
export default {
filters: {
date: convertDateToString,
},
The result of this shows the date as intended:
Globally registered filters
If we wanted to use this filter elsewhere, we could abstract this function into its own file and reference our filter once again, or, we could register thedatefilter globally inside of our application. Let's abstract ourconvertDateToStringfunction into its own file atsrc/filters/date/date.filter.js:
import moment from 'moment';
export const convertDateToString = value =
>
moment(String(value)).format('MM/DD/YYYY');
Afterwards we can define the filter inside of ourmain.jswith the following interface:Vue.filter('filterName', filterFunction()). As we've abstracted the function into its own file we can import it and define it like so:
import Vue from 'vue';
import App from './App.vue';
import { convertDateToString } from './filters/date/date.filter';
Vue.filter('date', convertDateToString);
new Vue({
el: '#app',
render: h =
>
h(App),
});
If you check our application again, you'll see that we get the same result as before. It is therefore important to consider where and how many times the filter will be used inside of the project. If you're using it on a specific component/instance (once) then you should place it locally; otherwise, place it globally.
Summary
In this chapter, we looked at many Vue directives and their usage. This now gives us the power to declaratively change the way our templates appear on screen, including ways to capture user input, hook into events, filter view data, and much more. This chapter should be used as a reference whenever you're looking to implement directives in a Vue.js application.
Component-based architecture is an important concept that allows us to build scalable projects that range from personal to enterprise.In the next chapter, we'll be looking at how we can create these reusable components to encapsulate pieces of functionality within our projects.