This chapter covers
Over the course of this book we’re going to build a complete web application: a webstore with product listings, a checkout process, an administrative interface, and more. The completed webstore may seem like it’s a long way off, especially if you’re new to web application development, but Vue allows you to start small, build on what you learn, and ship a sophisticated product in one smooth progression.
The key to Vue’s consistency at every stage of an application’s growth is the Vue instance. A Vue application is a Vue instance, Vue components are all Vue instances, and you can even extend Vue by creating instances with your own custom properties.
It’s impossible to touch on all the facets of the Vue instance in a single chapter, so we’ll build on the foundation we establish as our application evolves. As we explore new features in chapters to come, we’ll often refer to what we learn about the Vue instance and the Vue lifecycle in this chapter.
To begin our journey, we’re going to create the foundation of our webstore application, display its name, and create a single product listing. Our focus is on how we create a Vue application and the relationship of the data in our view-model to how it’s displayed in the view. Figure 2.1 shows what our application should look like by the end of this chapter.

If you tried the simple calculator sample in listing 1.2, technically this will be your second Vue application. You’re a seasoned veteran already!
Before we begin, download the vue-devtools plugin for your browser. You can find more information on how to download this plugin in appendix A.
At the heart of every Vue application, no matter how big or small, is the root Vue instance, Vue instance for short. Creating a root Vue instance is done by invoking the Vue constructor, new Vue(). The constructor bootstraps our application by compiling an HTML template for our app, initializing any instance data, and creating the data and event bindings that make our application interactive.
The Vue constructor accepts a single JavaScript object, known as the options object, new Vue({ /* options go here */ }). It’s our job to populate that object with everything the Vue constructor needs to bootstrap our application, but to start off we’re focusing on a single option, the el option.
The el option is used by Vue to specify a DOM element (hence el) where Vue will mount our application. Vue will locate the corresponding DOM element in our HTML and use it as the mount point for our application.
This code is the beginning of our webstore application. To make things easier to follow, I’ve included each code listing in its own file that you can download for this chapter. But to run the application, you’ll need to combine each snippet of code from each file into a single index.html file. Yes, the index.html file will get rather large as we progress through the book, and that’s normal. In future chapters, we’ll discuss ways of splitting our application into separate files.
If you’d like to see the completed application from this chapter, look for the index.html file that’s included with the code in the chapter-02 folder. (If you haven’t downloaded the code that accompanies this chapter, learn how and where to get it in appendix A.) Let’s create our first Vue application.
<html>
<head>
<title>Vue.js Pet Depot</title>
<script src="https://unpkg.com/vue"></script> 1
<link rel="stylesheet" type="text/css" href="assets/css/app.css"/> 2
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/
bootstrap.min.css" crossorigin="anonymous">
</head>
<body>
<div id="app"></div> 3
<script type="text/javascript">
var webstore = new Vue({ 4
el: '#app' 5
});
</script>
</body>
</html>
The markup contains a single div element with a CSS ID selector, #app. Vue uses that value to locate our div and mount the application to it. This selector matches the same syntax used by CSS (such as #id, .class).
Throughout this book we’ll use Bootstrap 3 for all layout and design. This works great and helps keep the focus on Vue.js. As of the time of writing, Bootstrap 4 was recently released, but because the focus of this book isn’t on design, I decided to leave Bootstrap 3 in. These examples will work on Bootstrap 4; but you may need to swap out several of the classes to the newer Bootstrap 4 classes if you do switch over. Keep that in mind.
If the CSS selector we provide resolves to more than one DOM element, Vue will mount the application to the first element that matches the selector. If we had an HTML document with three div elements, and we invoked the Vue constructor as new Vue({ el: 'div' }), Vue would mount the application at the first div element of the three.
If you need to run multiple Vue instances on a single page, you could mount them to different DOM elements by using unique selectors. This may seem like an odd practice, but if you use Vue to build small components, such as an image carousel or a webform, it’s easy to see how you could have several root Vue instances all running on a single page.
Let’s head over to Chrome and open the file you created for your first Vue application from listing 2.1, though it won’t yet render anything you can see in the main browser window. (After all, there’s no visible HTML!)
Once the page loads, open the JavaScript console if it isn’t already open, and hopefully you’ll see . . . <drum roll> . . . absolutely nothing (or perhaps a note about downloading vue-devtools if you haven’t already done so, or a note that you’re running Vue in development mode). Figure 2.2 shows what your console might look like.

Even as simple as our application is so far, we can still run into trouble when we load our file in Chrome. Here are two common issues to look out for when things don’t go as planned:
Tracking down errors the first few times can be frustrating, but after you’ve resolved a few errors the process will become more natural.
If you run into something you can’t figure out, or you find a particularly nasty error, you can check out the Help section of the Vue forum at https://forum.vuejs.org/c/help or ask for help in the Vue Gitter chat at https://gitter.im/vuejs/vue.
After Vue finishes initializing and mounting the application, it returns a reference to the root Vue instance, which we stored in the webstore variable. We can use that variable to inspect our application in the JavaScript console. Let’s use it now to make sure that our application is alive and well before continuing.
With the console open, enter webstore at the prompt. The result is a Vue object that we can inspect further in the console. For now, click the disclosure triangles
(
) to expand the object and look at the properties of our root Vue instance as seen in figure 2.3.

You may have to scroll around a bit, but you should be able to locate the el property we specified as part of our application’s options object. In future chapters, we’ll use the console to access our instance for debugging, manipulating data, and triggering behaviors in our application while it’s running, so we can validate that it behaves as expected. We can also use vue-devtools to peek inside our application while it’s running. (Again, if you don’t yet have vue-devtools installed, visit appendix A to learn how to install it.) Let’s see how it compares with using the JavaScript console. Figure 2.4 shows the different parts of the vue-devtools.

The vue-devtools extension provides big functionality for inspecting a Vue application, its data, and the relationship of its components. As an application grows in complexity, the searchable tree view in vue-devtools shows the relationship of components in a way the JavaScript console cannot. We’ll discuss more about Vue components and how they relate to the Vue instance in a later chapter.
We’ll frequently use both tools to zero in on problems with our application as we build it. In fact, we can use vue-devtools to discover another way to access our application instance in the JavaScript console as seen in figure 2.5.

When you select an instance in the tree view, as in figure 2.5, vue-devtools assigns a reference to the instance to the $vm0 variable. We can use $vm0 the same way we used our webstore variable. Try using $vm0 in the JavaScript console to see if you can inspect the root Vue instance
Having multiple ways to access the same instance may appear redundant, but it’s helpful to have both.
When we assigned our root Vue instance to the global variable webstore, we gave ourselves a way to refer to the application in other JavaScript code on the page. Doing so allows us to integrate with other libraries, frameworks, or our own code that may require a reference back to our application.
The Vue instance assigned to the $vm0 variable reflects the current selection made in vue-devtools. When an application is made up of hundreds, or even thousands of instances, it isn’t practical to declaratively assign each instance, so having a way to access specific instances that are created programmatically becomes indispensable when inspecting and debugging such a complex application.
Until now, our application has been a real snoozefest. Let’s liven it up by displaying data from our application instance in our application’s template. Remember, our Vue instance uses the DOM element we provide as the basis for its template.
We’re going to start by adding the name of our webstore. This will show us how to pass data into the Vue constructor, and how to bind that data to a view. In this listing let’s update the application code from listing 2.1.
<html>
<head>
<title>Vue.js Pet Depot</title>
<script src="https://unpkg.com/vue"></script> </head>
<body>
<div id="app">
<header> 1
<h1 v-text="sitename"></h1> 2
</header> 1
</div>
<script type="text/javascript">
var webstore = new Vue({
el: '#app', // <=== Don't forget this comma!
data: { 3
sitename: 'Vue.js Pet Depot' 4
} 3
});
</script>
</body>
</html>
We’ve added a data object to the options we pass into our Vue constructor. That data object contains a single property, sitename, which contains the name of our webstore.
Our site’s name needs a home, so we’ve also added a header element to the markup inside of the application’s root div element. On the heading element <h1>, we use a data binding element directive, v-text="sitename".
A v-text directive prints a string representation of the property it references. In this case, once our application is up and running we should see a header with the text “Vue.js Pet Depot” displayed inside it.
If you need to display a property value in the middle of a larger string, you can use Mustache syntax—{{ property-name }}—to bind to a property. To include the name of our webstore in a sentence, you might write <p>Welcome to {{ sitename }}</p>.
Vue only borrows the {{ ... }} syntax from Mustache for text interpolations, not from the entire Mustache specification. But if you’re curious where it comes from, visit the online manual at https://mustache.github.io/mustache.5.html.
With our data binding in place, let’s go see how our new header looks in the browser.
When you reload the application in Chrome, you should see the header proudly displaying the value of our sitename property as seen in figure 2.6. The visual appearance of our header is provided by the stylesheet in chapter-02/assets/css/app.css. We’ll use our stylesheet and Bootstrap to design our application. If you’d like to tinker with the appearance of the header, open that file and find the styles defined by header h1.

Vue automatically creates getter and setter functions for each property of the data object when it initializes our application. That gives us the ability to retrieve the current value of, or set a new value for, any of our instance’s properties without writing any additional code. To see these functions in action, let’s start by using the getter to print the value of the sitename property.
As you can see in figure 2.7, the getter and setter functions for our sitename property are exposed at the root level of our application instance. That lets us access the property from the JavaScript console, or from any other JavaScript that interacts with our application.

You can also see the property listed in vue-devtools when we select the <root> instance. Now let’s see what happens in figure 2.8 when we use the setter to set the value of sitename in the JavaScript console.

Once we provide a new value for sitename and hit Enter, the output in our header element is automatically updated. This is Vue’s event loop in action. Let’s look at the Vue lifecycle to see how and when changes to our data trigger updates to the view.
When a Vue application is first instantiated, it begins its journey through a sequence of events known collectively as the Vue lifecycle. Although a long-running Vue application will likely spend most of its time cycling within the event loop, much of the heavy lifting of the library itself occurs when an application is first created. Let’s take a high-level look at the lifecycle in figure 2.9.

Each phase builds upon the previous phase to create the Vue lifecycle. You may wonder what the virtual DOM is and how the render function works. The virtual DOM is a lightweight abstraction that represents the DOM. It mimics the DOM tree that’s normally accessed by the browser. Vue can make updates to the virtual DOM much quicker than the browser-specific DOM. The render function is the way Vue can display information to the user. For more information on the Vue instance and lifecycle hooks, please check out the official guides at https://vuejs.org/v2/guide/instance.html.
To see when our application instance passes through the different phases of the lifecycle, we can write callback functions for Vue’s lifecycle hooks. Let’s update the code in our main application file (index.html) in listing 2.3.
A hook is a function that gets “hooked” onto a part of the Vue library’s code. Whenever Vue reaches that part of the code during execution, it calls the function you define or continues along if there’s nothing to do.
var APP_LOG_LIFECYCLE_EVENTS = true; 1
var webstore = new Vue({
el: "#app",
data: {
sitename: "Vue.js Pet Depot",
},
beforeCreate: function() { 2
if (APP_LOG_LIFECYCLE_EVENTS) { 2
console.log("beforeCreate"); 2
} 2
}, 2
created: function() { 3
if (APP_LOG_LIFECYCLE_EVENTS) { 3
console.log("created"); 3
} 3
}, 3
beforeMount: function() { 4
if (APP_LOG_LIFECYCLE_EVENTS) { 4
console.log("beforeMount"); 4
} 4
}, 4
mounted: function() { 5
if (APP_LOG_LIFECYCLE_EVENTS) { 5
console.log("mounted"); 5
} 5
}, 5
beforeUpdate: function() { 6
if (APP_LOG_LIFECYCLE_EVENTS) { 6
console.log("beforeUpdate"); 6
} 6
}, 6
updated: function() { 7
if (APP_LOG_LIFECYCLE_EVENTS) { 7
console.log("updated"); 7
} 7
}, 7
beforeDestroy: function() { 8
if (APP_LOG_LIFECYCLE_EVENTS) { 8
console.log("beforeDestroy "); 8
} 8
}, 8
destroyed: function() { 9
if (APP_LOG_LIFECYCLE_EVENTS) { 9
console.log("destroyed"); 9
} 9
} 9
});
The first thing you’ll notice in listing 2.3 is that we’ve defined a variable, APP_LOG_LIFECYCLE_EVENTS, that we can use to enable or disable logging of lifecycle events. We define our variable outside the Vue instance, so it can be used globally by the root instance or any child components we write later. Also, if we defined it inside our application instance, it wouldn’t be available in the beforeCreate callback because it hasn’t yet been created!
APP_LOG_LIFECYCLE_EVENTS uses the uppercase syntax typically reserved for constant definition because, when we start using ECMAScript 6 later in the book, we’ll use the const feature to create constants. Planning ahead means we won’t have to do any find-and-replace to change the name in the rest of our code.
The remainder of the code defines functions that log each lifecycle event as it’s encountered. Let’s revisit our console exploration of the sitename property to see what happens in the Vue lifecycle.
If you open the console in Chrome and reload the app, you should immediately see the output from several of our callbacks as seen in figure 2.10.

As you might expect, the first four lifecycle hooks get triggered as Vue creates and mounts our application. To test the other hooks, we’ll need to interact with the console a bit. First, let’s trigger the update callbacks by setting a new name for our site. Figure 2.11 displays how this can be done.

When you change the sitename property, the update cycle kicks off as the data binding in the application’s header is updated with the new value. Now let’s destroy our application! (Don’t worry, it’ll come right back with a reload.) To trigger the last two lifecycle hooks, we use our instance’s $destroy method.
Special methods that Vue creates on our instance are available using the $ prefix. For more information on Vue’s lifecycle instance methods, you can visit the API documentation at https://vuejs.org/v2/api/#Instance-Methods-Lifecycle.
These last two hooks are typically used for cleanup activities in an application or component. If our application created an instance of a third-party library, we should call that library’s teardown code, or de-allocate any references to it manually, so that we avoid leaking memory allocated to our application. Figure 2.12 shows how calling the $destroy() instance method will trigger the destroy hooks.

The lifecycle hooks provide a great way to see what’s going on as an application runs, but I’m the first to admit that there’s repetitive, verbose code required to log messages to the console. Because they’re fairly bulky, I won’t include these debugging functions in code listings from here on, but we’ll occasionally use lifecycle hooks to explore new behavior or for functional reasons in the application itself.
If you do keep these hooks around, and the console gets too noisy with output, you can disable the logging by setting APP_LOG_LIFECYCLE_EVENTS to false. Bear in mind that you can disable them completely by changing the value in the index.html, or you can temporarily toggle logging on and off by setting the value at runtime using the JavaScript console.
Displaying the name of our webstore is a good start, but there are a few more aspects of displaying data in our markup that we should cover before moving on. Our webstore will display products in one of several ways: in a list, in a grid, as a featured product, and on its own individual product page. As we design and mark up each view, we’ll continue to use the same data, but we’ll use Vue’s functionality to manipulate it differently for each display without altering the underlying values or structure.
For now, we’re only going to display a single product, so let’s add a sample product to our data object.
data: {
sitename: "Vue.js Pet Depot",
product: { 1
id: 1001, 2
title: "Cat Food, 25lb bag", 2
description: "A 25 pound bag of <em>irresistible</em>,"+ 2
"organic goodness for your cat.", 2
price: 2000, 2
image: "assets/images/product-fullsize.png" 2
}
},
Adding a product object to our data option is relatively straightforward:
With our data in place, let’s get our view up to speed.
Now we can focus on adding the product markup to our HTML. Beneath the header element, we’ll add a main element that acts as the primary container for the content of our application. The main element, <main>, is a new addition to HTML5 and is meant to contain the primary content of a webpage or application.
For more information about the main element (and others), start by visiting www.quackit.com/html_5/tags/html_main_tag.cfm.
The product layout uses two columns so that the product image is displayed to the side of the product information (figure 2.13). Our stylesheet (chapter-02/assets/css/app.css) already has all the column styles defined, so we only need to include the appropriate class names in our markup.
<main>
<div class="row product">
<div class="col">
<figure>
<img v-bind:src="product.image"> 1
</figure>
</div>
<div class="col col-expand">
<h1 v-text="product.title"></h1> 2
<p v-text="product.description"></p> 2
<p v-text="product.price" class="price"></p> 2
</div>
</div>
</main>
One thing you’ll notice right away is the use of JavaScript dot notation in the data bindings. Because product is an object, we must provide each binding with the entire path to a property. Most of the properties of our product data—title, description and price—are bound using the v-text directives, the same way we bound the sitename property in the header.
The product’s image path introduces an attribute binding. We use the v-bind directive because element attributes cannot be bound using simple text interpolations. Any valid element attribute can be bound using the v-bind directive, but it’s important to note that there are special cases for styles, class names, and other scenarios that we’ll come to in future chapters.
You can use a shorthand for the v-bind directive. Instead of typing out v-bind every time you need to use it, you can remove the v-bind and type :, so instead of using v-bind:src=" ... ", you can type :src=" ... ".
We don’t need to restrict our data bindings to properties of our data. Vue allows us to use any valid JavaScript expression inside any of our bindings. A few examples using the code from listing 2.5 might be:
{{ product.title.toUpperCase() }} -> CAT FOOD, 25LB BAG
{{ product.title.substr(4,4) }} -> Food
{{ product.price - (product.price * 0.25) }} -> 1500
<img :src="product.image.replace('.png', '.jpg')"> -> <img src=" //assets/
images/product-fullsize.png">
Though using expressions in this way is convenient, it introduces logic into the view that’s almost always better off inside the JavaScript code of the application or component responsible for the view’s data. Additionally, expressions like this make it difficult to reason about where an application’s data gets manipulated, especially as an application’s complexity increases.
In general, using an inline expression is a great way to test something before formalizing that functionality within an application.
The next section and upcoming chapters introduce the best practices for manipulating, filtering, and deriving data from existing values without compromising the integrity of our views or application data. For details on what’s considered an expression, please visit https://vuejs.org/v2/guide/syntax.html#Using-JavaScript-Expressions.
Let’s flip over to Chrome, reload the page, and confirm that the product information is displayed as designed.

Uh oh, we’ve got a couple of things to work on:
Let’s solve that first issue first. What we need is an HTML directive, so let’s update the product markup using the v-html binding to output the product’s description as intended.
<main>
<div class="row product">
<div class="col">
<figure>
<img v-bind:src="product.image">
</figure>
</div>
<div class="col col-expand">
<h1 v-text="product.title"></h1>
<p v-html="product.description"></p> 1
<p v-text="product.price" class="price"></p>
</div>
</div>
</main>
Reloading the app in Chrome should now render the value of our product description as HTML and the emphasis tag should italicize the word “irresistible,” as shown in figure 2.14.

The v-html binding will render the bound property as raw HTML. This can be handy but should be used sparingly and only when the value is one you can trust. Now we need to fix the display of that pesky price value.
When we write code that inserts HTML directly into a view, we open our applications up to cross-site scripting (XSS) attacks.
At a high level, if a bad actor visits our site and saves malicious JavaScript in our database by using a form we haven’t sanitized, we’re vulnerable when we output that code to our HTML.
In general, best practice dictates that we should, at a minimum, follow basic principles regarding HTML and content:
For a comprehensive, clear overview of XSS, start with this article at https://excess-xss.com/, and for a deeper understanding of attacks and sample code for each exploit, consult this OWASP wiki at www.owasp.org/index.php/Cross-site_Scripting_(XSS).
The last thing left to do is to display our product’s price in a familiar format, not as a raw integer. Output filters let us apply formatting to a value before it’s displayed in our markup. The general format of an output filter is {{ property | filter }}. In our case, we want to format the product’s price to look like $20.00, rather than 2000.
Output filters are functions that receive a value, perform a formatting task, and return the formatted value for output. When used as part of a text interpolation, the value passed to the filter is the property we’re binding to.
All our output filters reside in the filters object of the options we pass to our Vue instance, so that’s where we’ll add our price formatter in the following listing.
var webstore = new Vue({
el: '#app',
data: { ... },
filters: { 1
formatPrice: function(price) { 2
if (!parseInt(price)) { return ""; } 3
if (price > 99999) { 4
var priceString = (price / 100).toFixed(2); 5
var priceArray = priceString.split("").reverse(); 6
var index = 3; 6
while (priceArray.length > index + 3) { 6
priceArray.splice(index+3, 0, ","); 6
index += 4; 6
} 6
return "$" + priceArray.reverse().join(""); 7
} else {
return "$" + (price / 100).toFixed(2); 8
}
}
}
});
The formatPrice function takes an integer and returns a string formatted to look like a U.S. dollar value. Generically, it will return a value similar to $12,345.67. Depending on the size of the integer provided, the function branches as follows:
You can find probably a gazillion ways to format a dollar figure that are more efficient, terse, or whatever quality you’re searching for. Here, I’ve tried to favor clarity over expediency. For an idea of how complex the issue is, and how many solutions there are, dive into this post at http://mng.bz/qusZ.
To use our shiny new filter function, we need to add it to the binding for our product’s price. We also need to update our price binding to use the Mustache-style binding to apply the filter, as shown next. Filters cannot be used with the v-text binding syntax.
<main>
<div class="row product">
<div class="col">
<figure>
<img v-bind:src="product.image">
</figure>
</div>
<div class="col col-expand">
<h1>{{ product.title }}</h1>
<p v-html="product.description"></p>
<p class="price"> 1
{{ product.price | formatPrice }} 1
</p> 1
</div>
</div>
</main>
Remember, bindings with filters have the generic form {{ property | filter }}, so we’ve updated our price binding accordingly, {{ product.price | formatPrice }}. Flip back over to Chrome, refresh, and voilà, we’ve got a formatted price as seen in figure 2.15.

We can see how our filter is applied to different product price values in real time if we tinker with our data in the console. To try different values, open the console and set the value of product.price with a statement such as webstore.product.price = 150000000.
Figure 2.16 shows what will occur after the product price is updated. Be sure to try out small (< 100) and large (> 10000000) values to be sure each is formatted correctly.

Use your knowledge from this chapter to answer this question:
See the solution in appendix B.