Vue.js: Getting Started
Hey there, I'm Chad Campbell, and today I'd like to talk with you about Vue.js. I've decided to write this course because I believe that Vue.js is a breath of fresh air in the increasingly complex world of web development. Vue.js has a focus on simplicity and speed. This focus helps you quickly build web apps that run fast. In this course, I'm going to show you how to build an app with Vue.js. To help drive home the concepts, we'll create a UI that will let you search for fictional beers and breweries. This UI is what's showing on the screen during this introduction. This UI, Google Chrome, and Visual Studio code will be used to show the key features of Vue.js. Plus, each module in this course has tons of examples which are in this repo. All of this is designed to help you learn how to use Vue.js to quickly create fast, running apps. In this module, you'll get a high-level overview of Vue.js. You'll see why Vue.js is compelling. From there, I'll address common concerns you or your friends may have about this framework. After that, we'll get to work. We'll walk through how to install and set up Vue.js in an app. Finally, this module will conclude by showing you how to initialize a Vue.js app. Let's begin.
Why Should I Care About Vue.js?
Vue.js, also known as just Vue, is a UI framework designed with simplicity in mind. Developers already have several popular UI frameworks to choose from. For that reason, I think it's important to consider why you might want to use Vue. These reasons will provide motivation for the rest of this course. In addition, this information will equip you if you want to promote your choice amongst others. It's important to remember that these are my opinions, and there's not a one-size-fits-all answer. Still, I like Vue at this time primarily because of its simplicity and its speed.
The Simplicity of Vue
Running Fast with Vue
Vue apps start fast and run fast. These two valuable speed indicators are met because of the size of Vue itself and its virtual document object model. As of the time of writing, the core Vue library was only 27.3 KB when gzipped. Once downloaded, the library is extracted into a small 74.8 KB package. This small size means that the library can be parsed and loaded quickly. While the speed that Vue can be downloaded and started is awesome, your Vue will spend most of its time actually running. The Vue is able to run quickly because of its virtual document object model. From a runtime performance perspective, changing the DOM is expensive. In fact, manipulating the DOM is typically the most expensive operation performed on the client side. It's expensive because the browser must recalculate the positions, shapes, and sizes of the elements on a web page. These recalculations block the user from using an app until it's done. This blocking behavior is not specific to Vue. Instead, it's performed by the browser and experienced with other client-side frameworks as well. To minimize the number of calculations, Vue implements a virtual DOM. A virtual DOM is like a lightweight copy of the actual DOM. The virtual DOM is responsible for efficiently determining what needs to be updated. It also batches those updates, which is faster than performing each update individually. To give you an idea of how Vue performs against other popular frameworks, let's take a look at a benchmarking chart. This chart shows the average time to complete a set of predefined tasks for benchmarking purposes. Shorter bars are better. This means that Vue executes the benchmark tasks faster than Angular and React. You can review the test yourself at this address. A faster runtime experience is something your users will appreciate. The simplicity of creating this faster experience is something that I believe you and other developers will appreciate. Still, it's important to consider a couple of other things too.
Other Considerations for Vue
In my opinion, there are additional considerations you should make when choosing a client-side framework. For example, I believe that you should consider browser support and licensing. I want to quickly discuss these other factors before discussing how to install Vue. New technology can be exciting; however, it's not much fun to release an awesome new app and get complaints due to browser compatibility issues. I know I don't want that, and I'm sure you don't want that either. For that reason, I want to show you which browsers Vue supports. As shown on the screen, Vue supports legacy browsers, including Internet Explorer 9 and up. Vue also support popular Evergreen browsers. Evergreen browsers are browsers that automatically update themselves to the latest version. These include Apple Safari on Mac OS, Google Chrome, Microsoft Edge, and Mozilla Firefox. On the mobile side, Vue supports Android and Safari on iOS. With browser support being this broad, a Vue app can reach virtually anyone. While having the ability to reach anyone is exciting, it's also important to consider if you can legally, due to licensing. Vue is available with the permissive and popular MIT license. This license is also used by jQuery and Angular; however, React uses the 3-clause BSD license with a Facebook addendum. The license used by React has been the subject of some concern and debate. I'm not a lawyer, and for that reason, I recommend you consult with your organization's legal representation as part of your framework decision process. However, personally, I've never received any pushback over something that was MIT-licensed. Personally, I strive to use permissive, well-defined, and easy to understand licenses like the MIT license, and that's another reason why I like Vue. Licensing and browser support are two important things to consider when choosing a framework. The runtime performance of a framework is also important. It's also helpful to use a framework that's both easy to learn and easy to use. Collectively, these things are good reasons to use Vue. Either way, once you've decided to use Vue, you'll need to install it and set it up.
Installing and Setting up Vue
Vue has a core library that is focused on app structure; however, modern apps often need more than just structure. They need to be able to do things like make HTTP requests to call web services. In fact, we need that ability in this course. For that reason, I'm going to show you how to install two libraries in this section. First, I'll show you how to install Vue itself. Then I'll show you how to install a library for making HTTP requests called Axios.
Vue is the core library that you'll need for all Vue apps. This library can be installed using a Content Delivery Network, also known as a CDN. Vue is available on several CDNs; however, the recommended CDN is called unpkg. Unpkg is recommended because Vue's project maintainers have stated that this CDN is kept in sync with the latest version of Vue. To install the latest version of Vue via unpkg, reference the library using this URL. This URL will always redirect you to the latest version of Vue. As of the time of writing, this URL redirected to version 2.2.5 or Vue. So the actual reference to version 2.2.5 looks like this; however, you can reference any available version by using a URL that fits this template. Once you have a path to the Vue core library, you're ready to include it in your app. To add it to your app, add a script tag towards the bottom of an HTML file. The actual script tag that we'll be using looks like this. In the context of an HTML file, your page should be set up like this. That's all you have to do to start up Vue. For more advanced scenarios, you can install Vue using a package manager like Bower or npm; however, those scenarios are beyond the scope of this course. What is in scope, and often needed, though, is a way to issue HTTP requests via Axios.
Axios is the recommended library for making HTTP requests from Vue. Axios is not part of the view project itself. Instead, it's simply one of the most popular HTTP client libraries available. Axios, like Vue, is available on unpkg. This means that, like Vue, you can reference the latest version of Axios using this URL. When you include Axios in the HTML file, you get the following. This gives us the ability to make HTTP requests in our Vue apps. This is an optional part of setting up a Vue app; however, referencing the Vue core library is a requirement for all Vue apps. Either way, once you've installed and set up Vue, you're ready to initialize an instance of Vue.
Initializing an Instance of Vue
To initialize an instance of Vue, invoke the Vue constructor function. This function brings an instance of Vue to life. In the rest of this course, we'll refer to an instance of Vue as just a view when it makes sense. This will move you faster through the course, and it's consistent with the role that an instance of Vue plays in an app. So to begin bringing our app, growler, to life, I'm going to instantiate a view, like this. There's really nothing exciting here. In fact, if a user visited this web page, growler wouldn't show anything. This code simply initializes growler. The Vue constructor was imported with the Vue.js core library that was explained in the last section. In this section, we're going to pass some options to the constructor to make growler more functional. In the rest of this module, I'm going to show you how to mount growler onto the DOM. This will serve as the bridge between the UI and data we want to show. After that, I'll explain the lifecycle of the Growler view. These two things are foundational to getting started with Vue, so let's get to it.
Mounting an Instance of Vue
Mounting is when Vue's virtual DOM is actually shown to the user. In other words, this is when your view becomes visible to the user. To mount an instance of Vue onto the DOM, use the el option in the Vue constructor. The el option identifies the HTML element the instance will be mounted onto. You have two choices when it comes to identifying the element. You can assign it to an HTML element like this, or as a convenience you can use a CSS selector like this. I recommend using the CSS selector approach simply because it's easier to read. Mounting an instance of Vue actually replaces the HTML DOM element with the Vue-generated DOM. For that reason, you should never set the el option to the HTML or BODY elements in a web page. Personally, I typically use a div. Either way, I'd now like to explain the lifecycle of a view.
Lifecycle of a View
Each view has its own lifecycle. This lifecycle has four main stages. In order of execution, these four stages are creation, mounting, updating, and destroy. Each of these four stages have two hooks that give you an opportunity to implement custom logic. The hooks provide access to before and after points of each stage. Each hook is appropriately named as beforeCreate and created, beforeMount and mounted, beforeUpdate and updated, and beforeDestroy and destroyed. At this point, you might want to know how a view progresses through each stage. I'm going to expand each of these four stages so we can go deeper into each stage of the lifecycle. The creation stage happens when you call the Vue constructor. You can literally call the Vue constructor with no configuration and the beforeCreate hook will fire. After any custom logic that you implement in the beforeCreate hook is executed, its state will get initialized. This includes loading properties, event handlers, data, and watchers. You may not know what each of these are yet. Don't worry. We'll discuss them in detail throughout this course. Still, once the view state is initialized, the created hook will fire. After the view has completed the creation stage, its template gets compiled. Once the template is compiled, the view's lifecycle moves into the mounting stage. The mounting stage is responsible for inserting the view into the DOM. First, the beforeMount hook is triggered. After any custom code is executed, the view's virtual DOM gets built. This virtual DOM then replaces the actual HTML DOM identified by the el property discussed in the last section. Remember, the virtual DOM is what empowers UI changes to happen so fast and so smooth. After this swap to the virtual DOM, the mounted hook gets fired. After the view completes the mounting stage, it begins listening for changes to the data. Your view will spend most of its time in this listening stage. But if any property in the initialized data object gets changed, the view goes through the updating stage. The updating stage is responsible for modifying the virtual DOM and re-rendering the UI as needed. If a data property that's bound to the UI is modified, the beforeUpdate hood is fired. Once this hook has completed executing any custom code, Vue continues evaluating the property change. Vue works to update the virtual DOM with the fewest number of changes necessary. These changes are referred to as patches. Vue's algorithm for determining DOM patches is inspired by an MIT-licensed open source project named snabbdom. Once the patches are generated, the virtual DOM gets updated. This means that the UI on the screen gets updated, and the updated hook gets fired. Your Vue will spend most, if not all, of its remaining life waiting for updates and events. If for some reason you need to tear down your view, Vue provides an instance method called destroy. When this is called, your view will enter the destroy stage. It will begin by firing the beforeDestroy hook. It will then tear down the virtual DOM. Then it will stop watching for any changes to the data. Finally, the Vue instance will trigger the destroyed hook, and the lifecycle will be complete. I want to point out that the destroy stage only happens if you specifically call the destroy method on the Vue instance. The destroy stage does not get called if a user navigates to another page, for example. For that reason, you shouldn't rely on the beforeDestroy or destroyed hooks getting called, unless you explicitly call the destroy method. The destroy stage completes the lifecycle of a view. As you saw in this module, this lifecycle begins when you instantiate an instance of Vue. An instance is created via the Vue constructor. This constructor is in the Vue.js core library, which you saw how to install and set up in this module. You also learned what makes Vue valuable. In the next module, we'll go deeper and continue with the Growler sample app. In the next module, we'll discuss how to create the actual UI portion with templates.
Creating Vue.js Templates
Defining Template Data
Loading Data Properties
Understanding Property Values
Binding Content to a Template
A template is made to show content. For example, think of the name of our fictional beer search engine, growler, as a piece of content. Earlier in this module, the name was added to the data object as a property called appName. Next, I'll show you how to bind appName as plain old text in a template. Then I'll expand on that concept and show you how to bind that name as HTML, to a template. Let's begin.
If you have some plain, unformatted text that you want to bind to a template, you can create a data binding. Vue has two syntaxes you can use to bind text to a template. The first is a semantic syntax that uses curly braces. The second is a declarative syntax that uses an attribute in your template. The choice of syntax is based primarily on your preferences. They both accomplish the same thing, and listen for changes to the properties they're bound to. There's also a way to create one-time bindings if you need to, though. Each of these topics will now be covered in detail.
You can create a data binding with a semantic syntax by using double curly braces. Oftentimes, these curly braces are referred to as mustaches. Mustaches are used in HTML elements as placeholders. They can exist with other HTML content, as shown here. They can be used as the sole child of an HTML element, like this. You can even use multiple mustache placeholders in an HTML element, as shown here. For now, let's focus on a single placeholder, though. Towards the end of the last section, the Growler view had been instantiated, like this. If this code were executed, Vue would look for mustaches and replace them with actual values. Vue would look inside each pair of mustaches and evaluate the code. In this case, the code is a variable called appName. Vue looks for appName in the data object on the Vue instance. If a property named appName is found, Vue replaces the mustaches with the value of the appName property at runtime. If the property is not found, the mustaches will be replaced with an empty string. A helpful and descriptive warning will also appear in your console window. Still, the process of going from mustaches to actual text is known as interpolation. This process also happens if you use declarative bindings.
Declarative bindings are created via directives. Directives are pre-defined tokens that tell Vue to do something specific to a DOM element. They provide a way to reactively update the DOM when an associated value changes. Vue has several baked-in directives, and all baked-in directives begin with v-. Since all of the directives included with Vue have the v- prefix, I'm going to call them by a different name, though. I'll refer to each directive without the v- prefix. For example, inside of saying v-text, I'll say text directive. I believ e this will make the course more enjoyable than hearing the phrase v- over and over again. Either way, the text directive empowers you to interpolate a property value as an HTML elements text. An example of declaratively binding to appName looks like this. At runtime, Vue assigns the text content property of the HTML element to the property value. This approach works great if you want to bind an element's entire content to a property. If you need to only bind to part of an element's content, you'll need to use the semantic syntax with mustaches. These two syntaxes may seem like just an abstraction, however, they do more than that. Remember, Vue manages a virtual DOM for you. Let's imagine that for some reason the value of appName needed to change at runtime. The UI would also change. To demonstrate, I'm going to show the app running in Google Chrome. Now, I'm going to open the console window and change the appName value to Growler with an exclamation point. Notice how the UI automatically reflected this change. You can play with this example yourself in the course repo found here. Dynamic UI updates can be really valuable if your app has some business logic, like the spreadsheet shown in the first module. Sometimes, though, you don't want the UI to change with the data changes. Sometimes, you just want to set it and forget it.
One Time Bindings
Let's be honest, the appName value probably doesn't need to change at runtime. For that reason, it doesn't make sense to listen for changes to appNames value. After all, listening for changes does require more computing under the covers, so to improve performance, you can add the once directive to an HTML element. To demonstrate, I'm going to switch over to Visual Studio code and add the once directive to the h2 element. Once the web page reloads, the one-time binding will take effect. Now, if I try to change the appName via the console window, you'll notice it doesn't change. The once directive tells Vue to render the element it's hosted in once, and only once. This directive informs the virtual DOM to skip an element during the updating stage of the lifecycle. It should be noted that any child of an element with the once directive will also be rendered only once. When the virtual DOM sees the once directive, it assumes that the rest of the branch should also only be rendered once. For that reason, make sure you understand the impact of this directive on your UI before using it. Still, the once directive does help optimize view performance. This can be useful when you're binding to plain text. It can also be useful if you're binding to HTML.
Binding to HTML
You can show plain HTML inside of an element by adding the HTML directive to an element. To demonstrate, I'm going to jump back to our example. Here you can see the appName property is now a link to the root of the site. Typically, you would never want to put HTML in your data, you want to keep your UI separate from your data, but in the real world, you may get data from a web service, which may include HTML. So if you do need to bind some HTML to a template, you can, but if I ran this specific example, you'd see the following. Instead of having a usable link, we get the HTML rendered as raw text. To get the rendered version of the HTML, use the html directive. I'm going to switch over to Visual Studio code and add the html directive to the h2 element. I'll assign the html directive to the appName property. I'm also going to remove the mustaches that were there, as they're no longer necessary. Now, if I look in Google Chrome, you'll see that the name now appears as a working link. The mustache bindings aren't necessary, because the html directive updates the innerHTML property of the element it's attached to. This replaces the visual tree within the element, including any mustaches. The HTML that gets inserted into the element is plain HTML. This means that you can't nest bindings. In other words, you can't put bindings and property values with HTML, like this. Well, technically you can do this, you'll just see something like this, instead of what you would expect. On a security related note, you should only bind to HTML that you trust. Dynamically rendered HTML can be a security hole targeted by cross-site scripting attackers. For that reason, don't bind to user-generated HTML, only bind to HTML that you trust. That's how you bind HTML to a template. It's slightly different than binding text to a template. Still, the binding techniques introduced with the text, once, and html directives showed you an important concept in Vue. That concept is called a directive, and it's also needed when binding to attributes in HTML elements.
Binding to HTML Attributes
Attributes are an important part of any HTML element. They are used to describe an HTML element. Vue made sure to consider HTML attributes in its design. I'm going to show you how to bind to HTML attributes. To do this, we'll build on the concept of directives explained in the last section. Specifically, I'll introduce the bind directive. Once established, I'll show you how to bind with inline CSS properties. Finally, I'll show you how to bind to CSS classes.
Introducing the Bind Directive
The bind directive is specifically designed to bind to HTML attributes. With the bind directive, you can bind data property values to HTML attributes. For example, what if the logo for growler was defined in a property named appLogo, like this. When I was learning Vue, my first instinct was to do this, however, mustaches can't be used inside of HTML attributes. Instead, you must use a bind directive on the source attribute, like this. If you're into the whole brevity thing, the bind directive also has a shorthand syntax. That syntax looks like this. This syntax removes the directive name, and leaves only the colon. The ability to bind to an HTML attribute is kept intact, though, which is good, because the bind directive is needed to bind with inline CSS properties.
Binding to CSS Properties
Binding to CSS Classes
Binding with Forms in Vue.js
An Introduction to Binding with Forms
Let me begin by saying, I'm really happy you've stuck with this course thus far. From this module forward, the fictional beer search engine is going to take shape much faster. In the last module, I showed you how to display data in a template. Showing data is a valuable part of any user interface. Collecting data is often just as important. The main way to collect data in a web page is through forms. In this module, I'm going to show you how to bind to forms in Vue. This module will begin by showing you how to use input bindings to collect data. When collecting data, you occasionally need to change the values input, like remove the whitespace, or perform other utility-type tasks on the input. For that reason, I'll also show you how to modify bound values. Finally, this module will conclude with a discussion on how to defer binding values to a later point in time. If you've been watching this course straight through, I encourage you to take a moment and stretch, perhaps grab a drink, or a snack, or take this opportunity to follow me on Twitter. Either way, I want you to get as much out of this course as you can. For that reason, make sure you're mentally fresh before starting the first section, Using Input Bindings.
Using Input Bindings
When you're ready to collect data, you need to create a two-way binding. Two-way bindings can be created using the model directive. This directive can be used with input tags, textarea tags, and select tags. This is a technical way of saying you can use the model directive with text fields, checkboxes, radio buttons, and dropdown lists. To ensure you know how to collect data in Vue, I'm going to cover each of these scenarios in detail.
Binding to Text Fields
In HTML, a text field is usually created using one of two tags. First, there's the input tag, second there's the textarea tag, I'll cover binding with both of these in this section. Most search engines have a way to enter a search query. In Growler, this role is filled with an HTML input element. In Vue, you can bind to an input element using the model directive, like this. This snippet shows how to bind to an HTML input element, Specifically, this snippet assumes there is a property in the data scope called query. The query property bridges the UI and the data with help from the model directive. In fact, if I take the information discussed in module 2 and expand on this example, like this, things begin to get interesting. This code sample binds the query property to the input element in the HTML template. To show why this is interesting, I'm going to switch over to Google Chrome. With Growler loaded, I'm going to start typing a query in the search field. Notice how this part of the UI is automatically updated as I type. This is the magic of two-way binding. This shows how change notifications, discussed in module 2, can impact your UI. If you had to wire this up by yourself, you'd have to track the value of the query, listen for the input event, and manually update the text shown in the UI. With Vue, all of this is handled for you. In the context of input fields that collect text input, Vue works with these types. You're probably familiar with some of these. Some of the less familiar ones were added with the HTML5 spec. You can see how each of these work by running the code provided in this course's exercise files, which are available here. Either way, binding to input elements lets you focus on the problems you're trying to solve. In addition, your code is just cleaner and easier to maintain. This approach also works with text areas. A text area is used to collect multi-line text input. For example, in an email, the subject line is often implemented as a standard text input, however, the body of an email usually needs multiple lines of text. For that reason, it would be best to implement this feature using a textarea like this. In this example, I'm using the concept of an email because search engines, like Growler, rarely need multi-line text fields, but I didn't want to use that as an excuse to skip over text areas. I wanted to give you the full tour of the input bindings available to you. Either way, notice in this example that the model directive is once again used for binding. At first glance, you may consider skipping the model directive and using mustaches for binding. It's natural to think that that would work, considering the textarea element has a closing tag, however, Vue doesn't support using mustaches in this context. Instead, you should continue to use the model directive for binding in a text area. Beyond that, there's not really anything else to know about binding to text areas. There is a bit more involved with binding to checkboxes, though.
Binding to Checkboxes
An HTML checkbox lets a user pick one value or another. In reality, there are two situations where using checkboxes should be considered. The first scenario is when you want the user to choose a single value, in other words, you want the user to make a yes or no, or either/or choice. The other situation is when you want a user to make multiple choices by creating a checkbox list. Either way, I'll show you how to bind to checkboxes in both of these situations, in this section. To bind a single value, just use the model directive. For example, by default, when the Growler beer search engine sees a query, it reads it as a simple query. If you were building a search engine, though, you might want to accept more complex queries. More complex queries are known as full or power queries in the search engine world. The details of these types of queries are beyond the scope of this course, however, they're explained in one of my other Pluralsight courses called Adding Search Abilities to your Apps with Azure Search. In that course, and more importantly, this course, a checkbox is used in the user interface to let the user switch between these two types of queries. The code for this looks like this. This code snippet looks almost identical to the query input field discussed earlier. There are only two differences. First, the type has been explicitly set to checkbox. This is to ensure the input element renders as a checkbox instead of a text field. This isn't a Vue thing, as much as it's an HTML thing. Beyond that, the only other difference is that this time we're binding to a property named isPowerSyntaxEnabled. The differences grow if you need to bind to multiple values, though. Binding to multiple values is useful if you want to let a user make multiple related choices. In Growler, a search is performed against a single searchIndex by default. A searchIndex is something like an entity. In the case of Growler, the searchIndexes are named beers and breweries. To let the user choose multiple search indexes at once, you could do something like this. This code sample binds the selected checkbox values to an array. When a user selects a checkbox, the value of the checkbox gets added to the searchIndexes array. The value is always pushed onto the array. This means that the value always gets added to the end of the array. If a user deselects a checkbox, the value gets removed from the array. To demonstrate how this works, I'm going to open one of the examples from the exercise files. As you can see, as I select and deselect the checkboxes, items are added and removed from the array. Now this is great for binding to values, but you might be looking at this hard-coded HTML and wonder if there's a way to dynamically generate the checkboxes themselves. There is, and we will discuss it later, in module 5. For now, I want to stay focused on binding to values and look at radio buttons.
Binding to Radio Buttons
HTML radio buttons are used to let someone choose one of several options. For example, the checkbox approach just discussed would let the user signal that they want to search beers and breweries, however, the user may really want to search only for beers or breweries. To accomplish this, you could use radio buttons, like this. In this snippet, the model directive is once again being used for binding. It's used to bind the radio buttons to the searchIndex property in the data model. The searchIndex property is a string that's explicitly set to the value beers. If I run this example, you can see that the Beers radio button is selected when the app starts. If I had left the searchIndex property empty or null, neither of these radio buttons would have been selected when the app started. Still, since both radio buttons bind to the searchIndex property, the property changes whenever one of the radio buttons is selected. Radio buttons are great in this scenario because Growler only has two searchIndexes. However, for situations where you have more choices, a different input field may be appropriate. For longer lists of choices, you might want to consider using a dropdown list.
Binding to Drop Down Lists
Dropdown lists in HTML can be created with a select element. This element is useful for two main scenarios. First, the select element can be used to let someone make a single choice. In other situations, the select element can be used to let someone make multiple choices. Both of these scenarios will be covered in this section. If you need to bind to a single choice in a dropdown list, you, once again, use the model directive, like this. In this example, the beers searchIndex is selected by default. This code is similar to the approach used when binding to radio buttons and checkboxes. In fact, the only real difference is in the HTML itself. In my opinion, this is a testament to the simplicity of learning Vue. This consistency appears whether you're binding to a single selection, or multiple selections. If you need to bind to multiple choices, you can simply follow the rules of HTML. This means that you add the multiple attribute to the select element, like this. In this example, I'm binding the selected options to the selectedSearchIndexes array. Earlier, when discussing checkboxes, I used an empty array, however, this time I'm initializing the array with two options. Now when the app starts, the beers and pubs choices will be preselected. This approach works with select elements in checkboxes. And that's really all there is to binding to dropdown lists. If you wanted to dynamically create the list of options, you can. Once again, I'll be covering that later, in module 5. For now, I want to continue discussed binding with form data, specifically, I want to discuss how to modify values bound to a form.
Modifying Bound Values
By default, Vue synchronizes a value input by the user with the data, whenever an input event is fired. Input events are triggered when an HTML input or select element collects user input. This occurs after the keypress HTML DOM event, but before the keyup event. Once the input event is fired, the value input by the user may go through one of several modifications. Out of the box, Vue provides two modifiers to lighten your development load. One modifier lets you trim string values as they're being input. The other modifier lets you automatically convert input values to numbers.
Using the Trim Modifier
Using the Number Modifier
Lazily Binding Values (Lazy Binding)
In the last section, I mentioned that Vue synchronizes user input whenever the onInput event is fired. As a general rule, this means any time a user presses a key, Vue will synchronize the user input with the data model. Sometimes, though, these continuous updates can be overkill. For example, in Growler, we wouldn't want to do a full search for beers every time a user entered a letter. That could be taxing on a server, and could lead to performance issues or additional cost, but it might make sense to do a full search when the input has changed. In addition to the onInput event, the HTML DOM has an onchange event. The onchange event fires when an input element's value is modified. This may sound identical to the onInput event, however, the difference lies in the fact that the onchange event fires after an input event has lost the focus. The impact is quite significant. For example, look at the following. In this example, the default binding behavior of the model directive is being used. As I type, notice how the query appears as I type it. If I change the binding to use the onchange approach, though, the behavior changes. Now, the query doesn't make it to the data model as I type. Instead, the data model updates after the input field loses focus. At that point, the query property is changed in the data model. This deferred approach is known as lazy binding, and this is how you implement it. In this example, I added the lazy modifier to the model directive. That's it. By appending the lazy modifier to the model directive, I described the behavior of the binding. That's really what modifiers do, they describe the behavior of a binding. The really cool part is that you can actually chain modifiers together. You might be thinking, waiting for a search query to complete before running a full search makes a lot of sense, but what if I need to remove the whitespace from a user's query. There are several ways you could do this. One way is to chain the trim modifier to the lazy modifier, like this. In this example, the trim modifier removes the whitespace after the query has changed. At this point, you might be wondering if the order of the modifiers matters. While testing the behavior while creating this course, I did not notice a difference. In my opinion, I suspect this might change. When I'm using modifiers in Vue, I order them assuming they get applied in order from left to right, meaning the lazy modifier would get applied, and then the trim modifier. This chaining approach also works with the number modifier. In this section, I explained how to lazily bind to form values. In this module, you also saw how to modify bound values. All of this was done within the context of using input bindings in forms within Vue. While binding to user input is important, it's also important to understand how to respond to user events. That's the topic of the next module.
Responding to User Events in Vue.js
Responding to User Events in Vue.js
The last module showed you how to bind with forms in Vue. Collecting data is an important part of many web apps. In many web apps, though, it's just as important to respond to user interactions. These interactions are also known as user events. In this module, I'll show you how to respond to user events in Vue. First, this module will begin by explaining how to listen for user-initiated events. From there, I'll go a bit deeper and show you how to tailor events to meet your needs. We'll discuss how to modify events. These topics are important to delivering interactive apps with Vue. For that reason, I encourage you to buckle up as we begin using event handlers.
Using Event Handlers
Defining Event Handlers
Examining Events and Passing Parameters
Altering Event Behaviors
As you interact with an app, you may learn that some things don't behave like you'd expect. You probably won't experience any issues with basic apps; however, as an app grows in size, it becomes more complex. This complexity can emerge as HTML elements nest within one another. While necessary, this nesting can introduce side effects that you may not have thought about. I want to help you proactively identify and address these side effects. To do this, I need to begin by explaining event propagation. Once you have an understanding of how events spread, I can show you how to modify their behavior. I'll do this by showing you how to react to keyboard and mouse events. Finally, I'll show you how to consider special keys, like Alt, Ctrl, and Shift. Let's begin.
Understanding Event Propagation
When events are invoked, they can start a chain reaction. This can happen because, by default, events in the HTML DOM are propagated through the visual tree. For example, imagine that the Search button in Growler was hosted in a dev element like this. In this snippet, this button is part of a visual tree that has at least two ancestors. Now, if a user clicks this button, the event can propagate in two different ways. The event can bubble up, or it can get captured. When an event bubbles, the element that was first selected invokes the event first. In the context of the Search button example, this means that the Search button would get first crack at handling the event. The event would then bubble up through the ancestor elements. Each ancestor could respond to the click event if it wanted to. This is the default approach used by events in Vue. There is a way to use event capturing if you want to, though.
Event capturing should be used if you want an event to be handled in the opposite order of event bubbling. Instead of the event target being first in the order of events, the event handling starts at the window object. The order then bubbles down through the visual tree all the way down to the target. Personally, I remember the difference in event ordering by using this phrase, bubble up, capture down. Still, you might wonder why does event capturing even exist? Event capturing was introduced by Netscape in the early days of the web. Microsoft introduced the event bubbling approach, which is the default approach used today. When the official W3C specification for events came out, it decided to support both approaches. Since Vue complements web technology so well, it naturally supports both event bubbling and event capturing. Personally, I can't think of a time when I've needed to use event capturing, but since your app may include a third party component that uses it, I want to discuss capturing for completeness. In Vue, event capturing can be applied on an element with a capture modifier. The capture modifier is used like the other modifiers shown in module 3. You simply append a dot after the name of the event and apply the name of the modifier. If the capture modifier were applied to the Search button code shown earlier, it would look like this. In this example, I'm using the capture modifier on three elements. By doing this, I ensure the event handlers are executed from top to bottom. In this example, the grandparentClick event handler will be fired first, then the parentClick event handler, and finally executeSearch. Notice, again that I applied the capture modifier to all three of these elements. Remember, the default approach is to bubble events up, so if I change the code snippet to look like this, something interesting happens. The order of events changes. Now the grandparentClick handler fires first, then the executeSearch handler, and lastly, parentClick. Yes, this order is probably not what you'd ever want. I created this example to show the impact of mixing propagation types. It's this type of behavior that makes me avoid using event capturing if I can. There are other modifiers that I do find quite useful, though, like the prevent modifier.
Using the Prevent Modifier
Using the Stop Modifier
Using the Self Modifier
The self modifier lets you declare that an element should trigger an event only if the element is the originator. This means that this modifier is only concerned with one element, the target. If the self modifier were applied to the Search button that's been used, it would look like this. In this example, the executeSearch method would run if the Search button were clicked. In addition, the parentClick and grandparentClick event handlers would also get executed. This is because the event still propagates up the tree when the self modifier is used; however, things get interesting if I move the self modifier to the parent element, like this. If I click the Search button now, the executeSearch method would run; however, the parentClick event would not execute because the originating event is not the development, but the event will continue to propagate up the tree and trigger the grandparentClick event handler. If I chose to click the parent div, the parentClick method would have been executed, and then the grandparentClick event handler. In addition to the self modifier, there's one more modifier that I'd like to discuss at this time.
Using the Once Modifier
The once modifier can be used if you want to run an event one, and only one time. In other words, if this modifier is applied, and the event is triggered, this same event won't get triggered by that element again. This is because the once modifier removes the event handler after the event has fired. This can be useful if the server is responsible for data validation. Even in that case, though, you still should update the UI to prevent a user from submitting a form twice. For example, let's disable the Search button and Search field after a user clicks Search. That code would look like this. In this example, the Search field and the Search button are disabled once the user clicks the Search button. These elements are disabled because each element's disabled attribute is bound to the isRunning flag. This flag is set to true once a user clicks the Search button. At that point, the form is submitted. By using the once modifier, the user is prevented from clicking the Search button multiple times. While this stops the button from getting clicked, it doesn't stop the event propagation. When you use the once modifier, it only detaches from the event handler of the containing element. For example, if the Search button would have been something like this, the behavior would have been different. In this case, if you click the Search button, you would see this alert box, and then this alert box, but if you click the Search button again, you would only see this alert box. If you disabled the Search button, though, the event would not propagate. Throughout this section, you've seen how event propagation can impact your view. You've also see the five modifiers that can be used to change the propagation behavior. Remembering each modifier's impact can be challenging. For that reason, I've summarized them in this slide. You may want to pause this video and print this slide out to use as a reference card. I also want to share that just like the modifiers mentioned in module 3, you can chain these modifiers together. So, if you wanted to ignore propagation altogether, you could do something like this. This example removes the parent element from the effects of propagation. This happened by chaining the stop and self modifiers together. The stop modifier ceases the event propagation, while the self modifier ensures that the event handler isn't triggered by any of the element's descendants. Event propagation is a great way to squeeze those last performance tweaks out of an app. Now that you have an understanding of event propagation, and the related event modifiers, I'd like to change topics. We're now going to discuss handling events triggered from key presses.
Reacting to Keyed Events
Creating Key Modifiers
Reacting to Mouse Button Events
Sometimes, mouse-specific actions are as important to the user experience as the keyboard. Vue provides three modifiers that are specific to the mouse. These modifiers are for the left, middle, and right buttons on a mouse. These three modifiers can be used with mouse-related events to respond accordingly. Specifically, all three of these modifiers can work with the mousedown and mouseup events. However, beyond the mousedown and mouseup events, these three modifiers provide limited support for the mouse-related events. For that reason, I'd like to discuss the left, middle, and right modifiers more closely so you can fully harness their power. The left modifier empowers you to respond to a user interacting with the left mouse button. For example, imagine that there's an area on the web page that you want to react to the user clicking on. In fact, I'm going to jump over to Google Chrome and show this. This example, which is part of the exercise files for this course, prints the mouse event when the left mouse button is used. This works in both of these boxes. Now, if I use the right mouse button in the box on the left, you'll see the event still gets triggered. This is because I haven't applied the left modifier to this element. However, the left modifier is applied with the event on the box on the right. You'll notice that when I right-click in this box nothing gets written to the event log. The implementation for this looks like this. On this slide, I'm using the mousedown event to respond to a user clicking on a div element. However, I've added the left modifier to the mousedown event. This has the impact of only reaching the onBlockClick event handler if the mousedown event was triggered via the left mouse button. A more familiar approach would be to use the click event like this. While this code technically works, I want to take it a step further and actually remove the left modifier. Once removed, this code becomes cleaner and looks like this. The reason this approach is better is because the click event only fires if the event was triggered by the left mouse button. In other words, using the left modifier with the click event is redundant. That's why on this slide I'm showing a question mark to represent the left modifier support for the click event. Beyond the click event, though, you can see that support is limited to the mousedown and mouseup event handlers. These two events are also only supported options for the middle mouse modifier. The middle mouse modifier lets you respond to a user interacting with the middle mouse button. This modifier is rarely used in an app. Personally, I've never needed it; however, I wanted to include it in case you needed to use it. Notably, as shown on this slide, there are only two mouse-related events that this modifier works with, the mousedown and mouseup events. You can add the middle modifier to one of these events, like this. There is nothing really exciting here. Once again, I wanted to mention the middle modifier for completeness. While you might never need to use the middle modifier, you may need to use the right modifier. The right modifier empowers you to respond to a user interacting with the right mouse button. I want to revisit Google Chrome to show the difference in behavior. In this example, I'm once again plugging into the mousedown event. You'll notice that when I use the right mouse button in the box on the right, an event is logged, but if I use the left mouse button, nothing gets logged. This is because I added the right mouse modifier to the mousedown event, like this. This approach is similar to the approach shown in the middle and left modifiers shown earlier; however, when I clicked in the box, you probably noticed that a context menu, like this, appeared. If you want to use the right modifier, there's a good chance you want to create your own context menu. Your initial instinct may be to leverage the click event; however, the right modifier doesn't work with the click event. Instead, you have to use the contextmenu event, like this. This example is a bit more involved. I want to break it down, though. First, look at the contextmenu event in the div element. Notice that I'm using the prevent modifier with the contextmenu event. Without the prevent modifier, the browser's default context menu would appear. However, by adding the prevent modifier, Vue bypasses the default event behavior. This means the browser's context menu won't appear. However, the onBlockClick event handler will still get executed. Notably, the right modifier isn't even used. That's because the contextmenu event only works with the right mouse button. While the right modifier could be used, it would just be redundant. The onBlockClick event handler is responsible for showing and positioning the context menu. The menu is rendered based on whether the showContextMenu property is set to true or not. You'll notice that the if directive is used to accomplish this. If you think you've missed something, don't worry; the if directive is discussed in the next module. Still, if the context menu is shown, it's positioned using the binding approach discussed in module 2. Each item in the context menu has its own event handler. Finally, when you focus on something outside of the menu, the context menu will go away. When activated, this context menu looks like this. While it's ugly, it does in fact work. There are additional enhancements that could be made to make it more robust. Those are more advanced topics that are beyond the scope of this module, though. The reason I wanted to show this context menu was to explain how to react to a user clicking the right mouse button on their mouse. You also saw how to use the middle and left modifiers. As discussed, some of these modifiers work with some mouse-related events, but not others. I've created this reference slide to help you quickly look up what events work with each modifier. You may want to pause this video and take a screenshot or print this screen out. Either way, Vue lets you go beyond using mouse buttons as modifiers. In fact, Vue also has modifiers that let you react to special keys.
Reacting to Special Keys
Personally, after learning to type in school, I learned about keyboard shortcuts. Popular shortcuts to copy and paste, like Ctrl+C and Ctrl+V, are still part of my everyday use. These shortcuts improve the experience of an app by giving the user more power. For that reason, you might want to consider adding keyboard shortcuts to your Vue apps with special keys. Special keys like Alt, Ctrl, and Shift are technically known as modifier keys. I'm going to refer to these modifier keys as special keys. The reason why is because we're already talking about modifiers in Vue. I'm concerned that if I use the term modifier keys instead of special keys, it will create confusion. Either way, special keys empower you to deliver keyboard shortcuts. This slide shows the modifiers Vue provides for special keys. The Alt, Ctrl, and Shift are commonly used keys in keyboard shortcuts. The meta key, is the Windows or Command key. Either way, let's create a keyboard shortcut in Growler. For example, the default behavior of the Search field is to run a search. Pretend that you wanted to add a keyboard shortcut for users who may want to run multiple searches at once. For example, what if we let the users run their search in another tab. That behavior would look like this. Now, I'm going to enter a query for Porter. Now if I press the Enter key, you'll see that I get one beer returned. Now I'm going to press Ctrl+Enter. Notice that another tab opened. If I switch to this tab, you'll see that my query ran in this tab. Now I'm going to close this tab. I'm going to go ahead and run multiple queries. I'm going to open each query in its own tab by using the Ctrl+Enter shortcut. First, I'll run a search for ale, then a search for stout, and finally, a search for pilsner. Now if I look in the tabs, you'll see that each query ran in its own tab. Part of implementing this feature involved implenting the keyboard shortcut, which I did, like this. This snippet is from the Growler sample app. This snippet brings several of the concepts we've been discussing, together. First, the trim modifier from module 3 is used to remove whitespace from the query as a user enters it. If a user presses the Enter key, the executeNewSearch function will get run. The enter and prevent modifiers discussed earlier in this module were chained together to properly handle the desired default behavior. As an added bonus, we included a keyboard shortcut that allows a user to press Enter and Ctrl to run the query in a new tab. That was made possible by chaining the control and enter modifiers together. As you can see, the special key modifiers and their mouse button counterparts help you deliver powerful features in your apps. By taking control of the event propagation approach, you can be sure to deliver a high-performing app. Collectively, these modifiers are powerful additions in Vue that let you enforce a separation between the UI and the logic. With modifiers, you don't have to worry about DOM event details. In this module, you learned how to respond to events by using event handlers. You also learned how to alter event behavior with modifiers. These two things explain how to respond to user events in Vue. In the context of the beer search engine, you now know how to collect the user query. You also know how to respond to the user clicking the Search button. When a user clicks the Search button, though, they'll expect to see the results of their query. That's the topic of the next module.
Conditional Rendering and Rendering of Lists
Conditional Rendering and Rendering of Lists
The last module showed you how to respond to user events in Vue. That discussion gave me the opportunity to show you how to handle things like button clicks and pressing keys. These types of interactions are used in most apps. In fact, in Growler, if you click the Search button or press the Enter key, you would expect a search to run. Once run, you would expect that query to return a list of results. In this module, I'm going to show you how to render those results. In this module, we're going to look at a number of directives in Vue that deal with rendering. This module will begin with a discussion on rendering elements conditionally. From there, we'll dive into rendering lists of items. As part of this, you'll see how to create item templates and react to list changes. Growler will really take shape in this module. For that reason, I'm really excited for this module. I think you should be too.
Rendering Elements Conditionally
Vue has several directives to help you show and hide elements when certain conditions are met. These directives relate to development concepts like if/else statements. Vue's conditional directives are best used in different situations. Some of these directives are better used when an app is loaded, while others are better used at runtime.
Rendering Conditionally on Load
Rendering Conditionally During Runtime
Vue provides several directives that empower you to conditionally render elements during runtime. One of these directives is a familiar if/else construct. There's also an additional directive called show. These directives serve unique purposes. For that reason, I'm going to cover these directives in detail in this section. The if/else directives let you conditionally render content based on an expression. If an expression returns a truthy value, the condition will be met, and the element will render. If the expression does not evaluate as truthy, the element will not be rendered. For example, look at the following sample. In this example, I'm showing the number of beers returned on a search in Growler. The cloak directive is used to hide any bindings until Growler is created. Once Growler has been created, these if/else directives determine what to render based on the number of beers found. If no beers were found, this descriptive block of text is shown. If a single beer was found, this block of text is shown. Finally, if more than a single beer was found, this block of text is shown. If you get the exercise files for this course and run this sample for yourself, you'll see a screen that looks like this. Each time you click the Search button, a random collection of beers will be generated. This could cause a different block in the if/else statement to get rendered. I bring this up, because each time the value changes, the elements and all of their children will be destroyed and reconstructed. It's not a big deal in this small example, but it's something to keep in mind from a performance perspective for more complex user interfaces. If you need to toggle something regularly, you may want to consider the show directive. The show directive is another option to conditionally show content at runtime. As shown in the following example, the show directive is similar to the if directive. Earlier, I used the if/else directive to conditionally show information. Those directives were appropriate in that case because I wanted to show a grammatically correct phrase. In this example, though, I'm using the show directive because I'm showing or hiding a block of elements. This approach is slightly different, because in this case only the display css property is changed. The show directive is a way to conditionally set the CSS display property at runtime. If the expression on this directive evaluates as falsy, the elements display property will be set to none. This also means that when you use the show directive, it will always render the element. The show directive is used to simply show or hide an HTML block. At this point, you may think the show and if directive are pretty similar. You might want to know what makes them differ from each other. While the if and show directives are similar, there are some important differences. First, the if/else directives are better for more complex logic, while the show directive is better for basic logic. That's why the if/else directives were used when showing the count of beer results. If it wasn't for the need to handle the case where a single beer was returned, a show directive would have been better. The reason why is because of rendering. The show directive always renders an element, however, the if directive only renders the content if an expression is truthy. In other words, the if directive conditionally renders elements. From this behavior, we can draw two conclusions. First, the if directive has higher toggling costs at runtime than the show directive. At runtime, the if directive destroys and recreates the virtual DOM as conditions change. On the other hand, the show directive just toggles the CSS display property, which is faster at runtime. The second conclusion is that if something is unlikely to change after a rendering, it's better to use an if directive. The show and if directives are important to keep in mind when rendering content conditionally at runtime. For the smoothest experience, use the cloak directive while your view is loading. Still, rendering individual items are one thing, rendering lists of items are another.
Rendering Lists of Items
Vue provides one directive that's focused on lists of items. That directive is called for. The for directive can be used in a number of ways. You can use the for directive to loop a specific number of times through an object, or through a list. I'm going to show you how to use the for directive to tackle each of these scenarios. I'm also going to show you what happens when you use the for directive and the if directive together.
Looping a Specific Number of Times
Traversing Object Properties
Iterating Through Arrays
Using v-for and v-if Together
When a for directive and an if directive are used on the same element, the for directive has higher precedence. This means that while a for directive is iterating, it will run first on each iteration. Then, the if directive will get run separately. This is handy if you only want to render specific items in a list. For example, in Growler, let's pretend that you wanted to let the user filter the beer results based on the alcohol by volume level. That might look something like this. This approach may be used with search results to filter out beers that have more alcohol than you prefer. You can see that as I slide the slider, the list of beers changes. This is happening because each beer in the underlying array is getting rendered conditionally at runtime. This rendering is happening via the HTML template shown on this slide. Here on the left, you can see an array of hard-coded beers. Each beer has a name and an alcohol by volume value. By default, we're setting the maximum alcohol by volume level at 7%. This property is bound to the slider in the HTML template. The array of beers is bound as list items using the for directive. While iterating, Vue will decide whether or not to render each beer, by comparing the current beer's abv to the maxAbv value. This works because the iteration happens before the comparison. In other words, the for directive takes precedence over the if directive. Using if directives on the same line as a for directive can help you create compact templates. Creating a compact template can help you keep your code clean if you're rendering lists of items. While the items I've shown up to this point have been static, that's not always the case. In fact, to deliver a smoother experience, you may need to change an array at runtime.
Detecting Array Changes
Using the Sort Function
The sort function puts elements in an array in order. For example, let's pretend that I have an array of beer names defined like this. If I applied the sort function like this, the array would be sorted in ascending order. This happens because, by default, the sort function treats each element in the array as a string, and orders elements in ascending order. Now, imagine the array were a list of alcohol by volume values. If that were the case, you would see a slightly different result. In fact, let's imagine there's an array called abv, which contains these values. Now, if I applied the sort function to this array, I would get this result. Notice that the numbers are not in numerical order. This is because, by default, the sort function treats each element in the array as a string, even if it's another type. to overcome this behavior, you must customize the sort function like this. On this slide, I'm using an override of the sort function. This override accepts a comparison function. During the sort operation, this function determines how two array elements should be ordered in relation to each other. These elements are passed in as the parameters. It is your responsibility to return a negative, 0 or positive value when comparing the elements. A negative value means that the first parameter should be in the array before the second parameter. A value of 0 means that there should be no change in the order. Finally, if a positive value is returned, the first parameter should be in the array after the second parameter. In the context of this slide, all of this was condensed down to this single line of code. At this point, you've seen how to use the sort function to arrange an array in ascending order. Now, imagine you wanted to show things in descending order. In that situation, you may want to use the reverse function.
Using the Reverse Function
The reverse function rearranges an array into the opposite direction. Put simply, the reverse function reverses an array. To demonstrate, let's revisit the array of beer names. This array has already been sorted in ascending order. If I apply the reverse function, the beer names will now appear in descending order. This isn't just for changing the direction of a sort, though. Let's take a smaller, unsorted array. If the reverse function were to be applied, it would appear like this. Notice in this example that the elements in the array are reversed. No sorting was applied before the arranging happened. Once again, the reverse function is purely for changing the direction of an array. If you need to manage elements in an array, you might consider the push and pop functions.
Pushing and Popping Array Items
The push function adds items to the end of an array. After an item is added to the array, the push function returns the updated length of the array. Let's revisit the list of beer names for a second. I could add a beer named Pope Lick Porter to this list with the push function, like this. Once added, the beers array becomes this. As you can see, the Pope Lick Porter was added to the end of the list. If I wanted to remove this beer, I could look to the pop function. The pop function removes the last element from an array. Once removed, the pop function returns the item that was removed from the array. Notice that this differs from the push function, which returned the array length. So if I took the array from the last slide, and then called the pop function, this would be the result. In addition, the pop function would return this, for use, if you needed it. The pop and push functions are useful for working with the end of an array. If you need to work with items at the beginning of an array, you may consider the shift and unshift functions.
Using the Shift and Unshift Function
To add items to the beginning of an array, you can use the unshift function. Personally, the name of this function has always made me do a double-take. The idea that I need to call a function name with the prefix of un to add something has always thrown me off. Still, just like the push function, once the item is added to the array, the unshift function will return the new length of the array. An example of adding a beer name to the beginning of an array would look like this. In this example, I'm adding the Pope Lick Porter to the start of the beers array. Once added, the beers array has a length of 4. That new length would get returned by the unshift function call. If I chose to remove the Pope Lick Porter that I just added, I could use the shift function. The shift function removes the first item of an array. Once removed, this function will return that item. This is similar to the pop function, except that instead of removing the last item, the shift function removes the first item. So if you wanted to remove the Pope Lick Porter from the array that was shown on the previous slide, you could, like this. As visible on this slide, the shift function removes the first item from the beers array. You've also seen how to remove items from the end of an array. If you need to remove items from the middle of an array, you need to do some splicing.
Splicing an Array
When it comes to array management, the splice function is the Swiss Army knife of array functions. The splice function lets you add and remove items to and from an array. You can add or remove items to or from the start, middle or end of an array. Since I've already shown you how to add and remove items from the start and end of an array, let's talk about the middle of an array. Let's once again visit a list of beers. In this list, we have four beers. Now, imagine that we wanted to remove the middle two beers. To remove the Hyote Chocolate Stout and the Ahool Ale, you could use the splice function like this. In this example, I'm using the splice function to remove two beers from the beers array. The first parameter is a required integer. This integer specifies where in the array to begin adding or removing items. The second parameter is optional, however, on this slide it means that I want to remove the two beers beginning at the first index. Had I not included it, all beers beginning with the first index would have been removed from the array. In either case, the splice function would return the removed items into their own array. The beers array itself would get updated to this. The splice function isn't just for removing items, though. You can actually use the splice function to insert items into an array. For example, let's take our updated list of beers and add the removed beers back into the array. We could do that like this. In this code snippet, I'm looping through the list of beers that were previously removed. The splice function is responsible for adding each beer back to the list. The first parameter specifies that I want to begin adding beers after the first item in the array. When adding items with the splice function, the second parameter is required. Since we don't want to remove any beers, I've set it to 0. Then, I'm passing in the name of the beer to add it to the list. Once completed, we get the following list of beers. Splicing is a great way to add and remove elements to an array, however, you can also use the splice function to update existing elements in an array.
Updating an Array Element
Reacting to Data Changes with Filters, Computed Properties, and Watchers
Before we dive into this final module, I want to personally thank you for watching this course. I hope you'll reach out to me on Twitter, @chadcampbell, and share your opinions about this course. After you've done that, I want to show you what you've learned, and how it all ties together. Then I'll show you some final tweaks that'll improve your app. Welcome to the final lap. In module 1, I mentioned that a UI for searching fictional beers and breweries would be used to drive home the concepts of this course. If you opened the code samples associated with this course, which are found here, you'll notice in the upper right corner is a button that says view full example. If you click this button, you'll see the following. I'm going to run a search for ale, and press Enter. With some results on the screen, I want to quickly show you what you've learned in this course. In module 2, I showed you how to use templates. That information was used to render the name of our fictional beer engine, Growler, as shown here. As a reminder, the color change is based on whether the app can connect to the internet or not. In module 3, I showed you how to bind to forms. You saw how to use the model directive to bind to HTML input elements like text fields. This information was used for the search field in Growler. You also saw how to use modifiers to handle common development chores and lighten your load. If you look next to the query field, you'll see a Search button. In module 4, you saw how to use event handlers. This empowered you to do things like handle a button click. In addition, you saw how to address common scenarios, like a user pressing the Enter key, which may be used in place of the Search button. In the case of Growler, if you did either of these things, you'd expect a search request to get fired off. While making the actual call to the search service is beyond the scope of this course, you still saw how to initiate that process. In addition, this sample app has the code to do that if you want to look at it. Going even further, if you want to learn how to create the actual search engine behind this button, please check out my Pluralsight course, Adding Search Abilities to Your Apps with Azure Search. Either way, once results were returned, you need a way to show them. In module 5, you saw how to conditionally render content. You saw how to render content conditionally at load time, and at runtime. You also saw how to render lists of items. This information could be used to render these results in the search engine. As you can see on the screen, the information you've learned in this course can be used to build a functioning app, however, there are a number of things that can be done to improve this app, specifically in regards to reacting to data changes. In this module, I'm going to show you how to react to data changes. Frist, I'll show you how to monitor data changes with watchers. Then, I'll show you how to render templates even faster with something called computed properties. Finally, I'll show you how to easily format data in a view using filters. This module is ordered this way because it matches how data changes get propagated. In fact, here's a diagram to reinforce the data flow. This diagram is here to help you remember the order of operations. Each of the items that will be discussed in this module is intended to help you write better code. In fact, each of these items are entirely optional. You can achieve similar results using the other material presented in this course, however, I believe that once you learn about each of these topics, you'll see better ways to react to data changes. With that said, buckle up, we're pushing towards the finish line.
Monitoring Data Changes with Watchers
In module 3, you learned how to collect data from a user via input bindings. In module 4, you learned how to respond to user events like button clicks. You could take the information from these two modules and react to a user event that likely results in a data change. This event could be something like a button click or a blur event on an input field. There is a more direct and more predicable approach, though. Vue provides a way to directly react to a change in the data itself. Watchers are special functions that let you react to data property changes. For any data property, you can create a watcher in the watch option of a Vue instance. To demonstrate, let's imagine that users could buy beers from a list of beers. As a matter of fact, I'm going to switch over to Google Chrome and show you what that screen would look like. Now, when I click the buy button, notice that the Subtotal field updates. Each time I click the buy button, the price of the beer is added to the Subtotal. I want to take a moment and explain the code powering this. To show you all of the code involved on the screen, I have to break this story down across multiple slides, so please bear with me. Let's begin by looking at the data that's driving this view. Each beer in the beers property is rendered as a table row, thanks to the for directive. Each table row includes the beer's name, price, and a button. If clicked, this button will pass the beer to the buy function. The buy function is defined in the methods option. That option is depicted by these ellipses. In reality, it looks like this. This slide has the methods option now visible. The ellipses represent the data object shown in the last slide. Here you can see the buy function triggered by the button in the template. If called, this function adds a beer to the user's shopping cart. When the shopping cart is updated, we want to update the subTotal property. Now, I could call the updateSubTotal function directly, if I wanted to, but in reality, there could be other functions that update the shopping cart also. Maybe users want to remove items from their cart, or change the number of beers. Either way, instead of calling the updateSubTotal function directly, it makes sense to call the function when the shopping cart itself changes. To do that, I'm going to create a watcher, as shown on this slide. The ellipses in this slide represent the methods option defined in the last slide. Notice the addition of the watch option, though. The watch option defines a list of watchers. Each key is the name of a property in the data object. This is the name of the property to monitor for data changes. If a data change happens, the keys value defines how to respond to that change. This definition includes the watcher's behavior and depth.
Defining a Watcher's Behavior'
Defining a Watcher's Depth
By default, watchers use a shallow monitoring approach. In other words, a watcher compares old and new values by reference. This means that properties nested in a watched property do not cause a change to be detected when they get changed. I want to demonstrate this point, because I believe it's important. Up to this point, the shopping cart property in the data object has just been an array. Let's expand the responsibility of the shopping cart, though. In fact, now it will have an array named items, which represent the items in the shopping cart. The shopping cart will also have a property named subTotal. The goal is that as beers are bought, the subtotal will get updated. If you're curious, we're basically refactoring code we've used earlier. I'm doing this just to demonstrate a scenario that I believe you'll run into in the real world. Now, if I run this code, you'll notice that the subtotal doesn't get updated when I click the buy button next to a beer. You might be thinking that this was working earlier, why isn't it working now? The reason why is because the items property is nested within the shopping cart, so by default, Vue won't be able to detect the addition of beers to the items array. This means that the subtotal never gets updated. However, I could update the watcher definition like this to react to changes in nested properties. This watcher syntax is slightly different than what's been used. The handler defines the function to call when the shoppingCart property changes. The notable part of this example, though, is the deep property. By setting this property to true, I'm telling Vue to watch for changes to properties nested within the shoppingCart property. This is set to false, by default, for performance reasons. For that reason, you should turn deep monitoring on only when it makes sense. After all, you shouldn't watch properties unless you have to. Watchers are a powerful way to react to data changes in a view. In general, watchers are useful for complex calculations, especially ones that require asynchronous calls. In most scenarios, especially ones that do not require complex calculations, you should use a computed property.
Faster Rendering with Computed Properties
A great user experience is a fast, responsive user experience. In order to meet this goal, you need to make implementation choices that will deliver the greatest performance. When rendering data in your UI, you can use methods to handle data conversions. However, when you call a method, the logic is run each time. If this logic is complex, or if it's called a lot of times, your app might render more slowly. Fortunately, Vue provides a way to cache properties once they've been computed. Computed properties are functions whose results are cached until their depending values change. This means that the first time a computed property is called, a result will be generated and cached. Then, anytime the computed property is called again, the cached value will be returned. Notably, the logic won't be reevaluated. Instead, a computed properties result will only be regenerated if a depending value changes. This means a faster runtime experience. Let's see how to initialize a computed property.
Initializing Computed Properties
To initialize a computed property, you set up something that looks like a method. To demonstrate, let's look at an example. In this example, I have a computed property named isOnline. This property is a flag that signals if the search engine is able to access the internet, or not. It provides a simple yes or no, based on the value of canConnect. By default, this property is set to false when the app starts. Once the app is created, the Axios library mentioned in module 1 is used to see if the app can reach a website. The result of that request is used to set the canConnect property. When the canConnect property changes, the isOnline computed property will get refreshed. In other words, the cached value will be replaced with the new value. This results in the UI bindings getting updated as well. So, if the can Connect property gets set to false, the UI will show no, and if the canConnect property is set to true, the UI will show yes. Computed properties are great when you want to cache values. That's why, by default, they strictly retrieve values. Basically, computed properties are getters by default, but if you want to expand a computed property to be a getter and a setter, you can. In fact, you can use a computed property as an accessor.
Using Computed Properties as Accessors
Computed properties can be used as accessors. Accessors are computed properties that can get or set property values. This concept may sound familiar, in fact, accessors are found in some form in other popular languages like C#, C++, and Java. To see what Vue's version of an accessor looks like, let's do a before and after of the isOnline computed property. Here on the left, you can see the isOnline computed property used in the last section. Now, I could expand this code and explicitly declare that this computed property is a getter by defining a get function like this. This approach does not change the behavior of the computed property. Rather, it's a more verbose way of achieving the same goal. Now, if I wanted to set the canConnect value, I could by adding a set function, like this. Now, the isOnline computed property lets you both get and set the canConnect data value. Notice how the set function takes in a parameter called newValue. This parameter is the value that you want to change a property to. This empowers you to use the existing value as a before value, and the newValue parameter as the after value. Then, when the new value is set to the canConnect data property value, the get function is rerun. The reason why is because canConnect is the dependency property for the computed property. This, in turn, means the UI will get updated to reflect the data change. Expanding a computed property to an accessor is great when you need to do more than retrieve a value. In fact, using a setter is a great way to impose validation on values, as they're being set. The big reason to use a computed property though, is for its caching abilities, which can provide a performance boost. In most cases, a computed property is the way to go, however, for basic text transformations, you may want to consider a filter.
Formatting with Filters
When working on an app, you may need to perform some basic transformations. For example, in Growler, each beer has International Beer Units, or IBUs, associated with it. Pretend for a second that that data looks like this. Well, if that were the case, you may want to transform the data in two ways. First, you may want to remove the periods. Next, you may want to make the text upper case. If you did these two things, each value would become this. These kinds of basic text transformations are best implemented as filters. Filters are a special type of function in Vue. They're intended to be used for common text conversions. This includes things like converting a string to lowercase, perhaps reversing a string, or, as seen in the case of our beer search engine, removing periods and converting the text to uppercase. If you wanted to make a filter that meets the needs of the last example, You'd have a filter that looks like this. This slide has a predefined list of beers squished here in an array called results. The beer listed here has its international beer units available through the ibu property. In the HTML, a for directive is used to loop through the results. For each result, mustaches are used to create a semantic binding on the name. Mustaches are again used to bind the IBUs to the template. I'm using mustaches, because, as of the time of writing, filters could not be used with the HTML or text directives. Either way, inside of these mustaches there's a filter named convertIBU being applied.
The convertIBU filter is defined in an instance-level object called filters. This object is at the same level as the data and methods objects you've already seen in this course. Inside of the filters object is a comma-delimited list of functions that can be used in a binding. In this case, only one filter named convertIBU is defined. This function takes in a value which is automatically passed in. The periods are then removed from the value, and it's converted to uppercase. That's it. If you wanted to pass in an additional parameter, you could, like this. In this example, I'm passing in a parameter called empty. This parameter's value is used if a beer doesn't have an IBU value. In this case, two dashes will be used instead of an empty string. Still, the value that the filter is being applied to is automatically passed into the function. Whether you pass in additional parameters or not, the value is always the first parameter passed to a filter, well, unless you're calling a filter programmatically, that is.
Programmatically Calling a Filter
Chaining Filters Together
Just like the modifiers explained in module 3, you can also chain filters together. Instead of using a period, though, as in the case with modifiers, you use a pipe. Let's pretend for a second that the filter definitions were changed one more time. For example, I'll make each filter its own unit, like this. Now, there are three distinct filters, convertIBU, removePeriods, and toUpperCase. Each of these filters is being called in sequence by the HTML template shown on the right half of the screen. The result of the convertIBU filter is passed as the value into the removePeriods filter. Then, the result of the removePeriods filter is passed as the value to the toUpperCase filter. After all of these filters have executed, the result is rendered in the HTML. Filters are a nice way to handle basic text transformations. At this point, you may be wondering, why use a filter instead of just calling a method?
Comparing Filters to Methods
Filters and methods are closely related. In fact, you can use methods to get the same result as a filter, however, filters serve a slightly different purposes. Filters are intended to be used in your HTML template. With this intent, there are two rules for defining filters. First, filters should only take in a value and return a new value. Along with this, filters should not change the value of any properties in a view. The convertIBU filter shown met both of these rules. Beyond the intended purpose, though, filters are just easier to read. Imagine the functions called by the convertIBU filters were methods. In that case, you'd call them like this. When compared to the version that uses filters, which do you find easier to read? Personally, I find the filter version easier to read. It's more readable because of the chaining abilities. You don't have to mentally parse the code, you just read the code from left to right, which is more natural. If you're wondering whether you should use a filter or a method, there is another test. In general, filters are intended to be used across views, however, a method is specific to the instance. If you intend to reuse the code, you may want to ask yourself, if it should be a filter. Filters are a great way to handle basic text transformations. For more complex data transformations, a computed property is more appropriate. Finally, if you need to handle asynchronous data operations, you should consider a watcher. I've tried to summarize the abilities of each construct on this slide. If you would like to pause the video and take a screenshot or print this out, it may be handy for you. Either way, in this module, you saw how to use watchers, computed properties, and filters to react to data changes. This concludes the content for this course. There are a number of valuable topics that are outside the scope of this course. For example, we barely scratched the surface of Axios. There are also more advanced topics like components, transitions, routing, state management, and server-side rendering. The reason these topics were not part of this course, is because this course was focused on getting you started with Vue.js. If you would like to learn about these more advanced topics, as well as other topics, please let me know on Twitter, @chadcampbell. If there is enough interest, I'd be happy to put together a follow-up course. Once again, I sincerely want to thank you for watching this course. I hope you'll take a moment to review the course. That lets me know if you found this course helpful. Best wishes on building your apps with Vue.js.