Vue.js: Getting Started
Introducing Vue.js
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
Vue promotes itself as an approachable framework. This framework is approachable because of how few prerequisites there are. If you know HTML, CSS, and JavaScript, you can hit the ground running very quickly. This is similar to what jQuery did when it was introduced. JQuery was introduced in 2006. Since then, it's been one of the most popular JavaScript libraries in use. This library became popular because it empowered people to easily do amazing things. It let someone focus on solving problems instead of worrying about design patterns, tool chains, and other complexities. These complexities have run rampant in other frameworks. In some situations, these complexities are necessary; however, a lot of times they simply take you away from what you're trying to accomplish. So, if jQuery is powerful and easy, why consider using Vue? As a web page or app grows, it becomes more complex. This complexity can make an app error prone and difficult to maintain. This challenge is accurately depicted in a quote I saw on Twitter which said if you don't actively fight for simplicity in software, complexity will win, and it will suck. Vue helps you fight this good fight with templates and declarative bindings. Templates are a big part of Vue. Templates separate the UI from the data and business logic. The data and business logic get written with JavaScript. The UI is defined by HTML and CSS. Vue is then responsible for compiling the templates into what the user sees. To remember the purpose of a template, I think back to my childhood. When I was a kid, I collected basketball cards. Each basketball card could have a picture of a basketball player and their stats on it. In the context of Vue, the stats would be the data. The picture in details would be the template. The two come together to make the basketball card for a player. The code on the screen shows data for a single basketball player. Imagine if we wanted to show the cards for all 12 players on a team, though. If we had to manually create the HTML for each player, that would be a lot of HTML to create. Going one step further, imagine if we wanted to show players for 30 or more teams. That's too much work, and most likely, next seasons the layout and style of the basketball cards will change. That would be a lot of HTML to change. A Template insulates you from two things. First, a template minimizes the amount of code you have to write. With a template, you don't have to write similar code over and over again. Second, templates protect you from changes. With a template, you only have to update the HTML once. Instead of the UI being driven by the HTML, the UI is driven by the data. The UI and the data are bound together by declarative bindings. A declarative binding is the glue that holds the UI and the data together. To understand why this is so valuable, I want you to imagine a spreadsheet that calculates sales tax. This spreadsheet has a design that consists of fonts, colors, and other formatting details. the spreadsheet also has raw data in each cell, and some cells have formulas, which are a kind of business logic. If you change the text color of a spreadsheet cell, you don't expect the actual data to change. You also wouldn't expect the results of the formulas to change either, but if you change the actual data, you would totally expect the cell's data to change. You would also expect the formulas to update the results without you having to do anything. This real-world scenario gives you a visual for why declarative bindings are so valuable. Declarative bindings are an important part of templating. They enable a separation of concerns that simplifies development. If you're on a team with other developers, these concepts enable you to work on the design or UI, while other team members focus on the back end. You can just make up some fake data until the real stuff is available. Declarative bindings reduce the amount of code you have to write. Declarative bindings also remove the burden of directly managing the DOM when the data changes. As you saw in the spreadsheet, the sales tax total just updated when the related sales were updated. Without declarative bindings, you would have to write the code to manually update the value in the cell. With declarative bindings, though, the update happens automatically, just like it does in a spreadsheet. Declarative bindings are one way that Vue helps simplify your development. Vue's support for templates also streamlines your development. These topics will be discussed in much more detail beginning in module 2. For now, I just wanted to share what they are. I also wanted to point out that you get these things without having to learn specific design patterns or complex tool chains. This simplified approach is why some, like Peter Jang, are calling Vue the next jQuery. While that's a bold statement, I do believe Vue's popularity will only skyrocket. I believe this because of how easy Vue is to learn and develop with. I also believe this because of how easy the app code is to maintain. In addition to these things, I believe Vue is valuable because of how fast it is.
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.
Installing Vue.js
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.
Installing 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
Introducing Templates
The last module showed you how to initialize an instance of Vue. That instance of Vue represented our fictional beer search engine called Growler. In this module, we'll continue to create Growler, and begin to work on its visual structure. That structure is known as a template. Templates in Vue are created with good, old-fashioned HTML. In fact, templates in Vue are HTML specification compliant. This is a fancy way of saying valid HTML. Still, the data that drives these templates are defined in the Vue instance itself. This module will begin with a discussion about defining template data. This data can be used in a number of ways. For example, in this module, you'll see how to bind the data as content to a template. You'll also see how to bind the data to HTML attributes. Finally, this module will conclude by showing you how to use data properties in JavaScript expressions. This module will begin to pick up the pace of the course. I encourage you to stick with it, as you'll begin to see the Growler search engine take shape.
Defining Template Data
Templates are driven by data. In the first module, the Growler view was initialized with this code. To drive this Vue, we need some data. That's the role of the data property. The data property is an object with two purposes. At design time, which is when you're developing your view, the data property represents the schema. At runtime, the data property serves at the model behind an instance of the Vue. To see what the data property looks like in action, I'll expand on the growler initialization code like this. The significance of this example is that the data property is assigned to a plain, old JavaScript object. This is also known as a POJO. There's nothing here that's unique to Vue. This means that you can access Vue data from outside of your Vue, like this. As a nicety, Vue automatically creates shortcuts to data properties for you. This means that you can work with the Vue's data using code like this. This may not seem important, but if you've tried to access a property like this in other UI frameworks, you'll probably find this approach refreshing. If you're new to UI frameworks, this code should reinforce the idea that one of Vue's core benefits is its simplicity. This code shows how Vue plays nicely with established web standards like JavaScript. In fact, JavaScript is at the heart of when properties are loaded, named, and assigned values.
Loading Data Properties
Vue loads data properties during the creation stage. For each property in the data object, Vue uses JavaScript's built-in Object.defineProperty method to create getters and setters. When Vue does this, it enables change notification and dependency tracking under the covers. These two technical terms are a way of saying that when a data property changes, everything that relies on the property will know about the change. This is also known as making the property reactive. While extremely advantageous, there are two caveats you should be aware of. First, you can only modify properties that are defined in the data object. You can't add properties to the data object at runtime. You also can't remove properties from the data object at runtime. The reason why is because data properties are converted to getters and setters during the creation stage of a view's lifecycle. Vue doesn't have a way to detect the addition or removal of properties. This is due to the limitations in JavaScript itself. While this may seem limiting, I think this is a benefit. Remember, Vue is focused on being approachable and easy to use. Since properties can't be added or deleted from a view at runtime, it forces you to think ahead. This also means that the data object for your view serves as its schema. If you have to maintain this code later, or another developer needs to work with it, the schema simplifies this process. If you know that you'll need a property in your view eventually, but not when the view is created, don't worry, just assign the property to an empty value or null. The second caveat with getters and setters involves your development experience. If you use the browser console during development, you'll notice that data properties with JavaScript objects are formatted differently. For example, later in this course, growler will show how to search fictional beers. To search for those beers, the view will hit a web service. The details for that web service will be stored in a property named searchService. Now, if you printed searchService in the console window, you might expect something like this. This is how a JavaScript object is usually formatted in a console window. In it, you can see the names of each property and their values, however, remember, Vue adds getters and setters to make the data properties reactive. This changes the format of a property in the console window to something that looks like this. This makes it more difficult to inspect data in your view. It's probably not the development experience you want. To work around this side effect, install an extension in Google Chrome called vue-devtools. Once installed, you can quickly examine the data in your view. Now, instead of seeing getters and setters, you'll see something like this. This is a much better development experience. You can once again see something that resembles a JavaScript object. You can clearly see actual property names, which brings us to our next topic.
Naming Properties
Each property in the data object has a name. The name is what's used in the Vue template to reference a property value. The name can be whatever you want, as long as it's consistent with JavaScript variable naming rules. This means that your properties can be named with letters, digits, dollar signs, and underscores, should start with a letter, are case-sensitive, and cannot be reserved words. There is one naming rule that's specific to Vue though. Property names should not start with dollar signs or underscores. The reason why is because property names that start with dollar signs or underscores can conflict with Vue's internal operations. Those are really the only rules when it comes to naming properties in a data object. The more interesting details happen with the property values.
Understanding Property Values
Each property in the data object has a value. The value of a property is what will be shown in the view. If you modify a value, the UI will asynchronously change to reflect the change in the value. That's why the dependency tracking and change notifications mentioned earlier are so important. Data property values should just be data. That sounds redundant, but it's true. Once again, the focus is on simplicity. For that reason, the data object supports JavaScript primitive values like numbers, strings, dates, and arrays. However, the data object does not support native objects. Vue actually ignores native objects with number, string, date, and array types. For that reason, you should stick with raw data. This simplifies state management, and is more intuitive anyways. When it comes to understanding property values, that pretty much sums it up. In this section, you also saw property naming rules, and learned how properties are loaded. Together, these set up the schema for your view. When your data object is defined, you can begin binding it to a template.
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.
Binding Text
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.
Semantic Bindings
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
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
You should strive to keep your design separate from your logic. Sometimes, though, the two worlds collide. If this happens, you might find yourself in a situation where you need to bind to an HTML element style attribute. You can bind to the style attribute with the bind directive. When binding to the style attribute, you must choose between two approaches. You must decide if you're going to get CSS properties from a JavaScript object or from a JavaScript array. I'll cover both of these approaches in this section. You can get CSS properties from a JavaScript object during bindings. This approach looks very similar to the traditional CSS approach, except the style string is a JavaScript object. Each property name of the object represents the name of a CSS property. The value associated with each property can be a property name from the Vue's data object, or a static value. To demonstrate, here is an example that sets the color of the appName. Notice in this example that the style binding references a property named color. In this case, we're binding to the CSS color property, however, this brings us to a problem. What if we wanted to bind to the family property? This is a problem, because you can't use dashes in JavaScript variable names. If you need to set a CSS property in a style binding, whose name is separated by dashes, you're out of luck. Just kidding. I wanted to make sure you're still paying attention. You can actually work around this limitation by changing the property name from kabob casing, which means the dashed approach, to camel-casing, so font-family becomes fontFamily. This isn't a Vue-specific thing. Instead, it's consistent with the JavaScript naming of CSS properties. This syntax is great because it lets you mix dynamic property values with hard-coded static values. For example, if I wanted to set the margin property to 0, I can, like this. We don't expect the margin to change, so this is a realistic example. At this point, the style attribute is starting to become cluttered, though. Thankfully, this style attribute's value can be refactored to the data property, like this. As you can see, this cleans up our code a bit. That's all there is to binding to CSS properties with the JavaScript object. You can also bind to CSS properties with an array. Styles are often shared across multiple elements. For example, at this time, the title of the app has an orangish color. That color may be shared by other elements and referred to as an accent color. At the same time, the header tags in the app may use shared styles too. For these scenarios, where you need to use multiple style definitions during binding, you can use a JavaScript array, like this. In this example, the view has two JavaScript objects with CSS property settings. Both of these JavaScript objects are bound the style attribute of the HTML element via a JavaScript array. When an array is used, CSS properties are stacked from left to right. This means that the latest property setting has the greatest precedence. In other words, if the headers object in this example had defined a color property with the value green, the name Growler would be green instead of orange. Binding CSS properties through JavaScript arrays and objects can be handy as your app becomes more dynamic. However, as a general rule, you should strive to keep your CSS separate from your data as much as possible. For this reason, instead of defining CSS property values in the data object, you might want to define them in standard CSS classes and bind to those classes.
Binding to CSS Classes
Vue lets you bind directly to CSS classes. This is an improvement over binding to CSS properties, because it helps you maintain separation between your design and your data. This separation helps you keep your code clean and maintainable. To demonstrate, the code that was just shown while discussing binding to CSS properties looked like this. When refactored to use CSS classes, it becomes this. At first glance, it may look like we just moved some cod around, which isn't really better, however, what's really happening here is, we've separated the UI from the data. The data in the left portion of the screen is just JavaScript, while the design is defined in the right part of the screen with HTML and CSS. This approach complements the HTML and CSS standards more naturally. Instead of trying to generate HTML and CSS form JavaScript, you're complementing the HTML and CSS. This approach works by prepending the class attribute with the bind directive. This is similar to what was completed when we were binding to the style attribute. In a similar way, you combine the class attribute to a JavaScript array, or a JavaScript object. There are some subtle differences, though, that I'd like to cover in this section. The example on the screen binds the class attribute to a JavaScript array. Each element in the array is the name of a property in the underlying data object. The property references the name of an actual CSS class. At runtime, this h2 element actually becomes this. We could have put the entire JavaScript array in the Vue's data, like this, if we wanted to, there's no difference. It's really just a personal preference of which syntax to use. While you can use an array for CSS classes, you can also use a JavaScript object. Binding to CSS property values like we did earlier, was intuitive. Each property name in the JavaScript object was the name of a CSS property, and the value was a recognized CSS value. However, binding to CSS class names via a JavaScript object may seem odd at first. When binding CSS classes via a JavaScript object, it's not really obvious what the name and value of each property represents. When binding CSS classes via a JavaScript object, the name of each property is the name of a CSS class. The value of the property acts as a flag to determine whether or not to apply the class to the element. In other words, this is a way to conditionally apply CSS classes to an element. To demonstrate, this code is the syntax for binding the header CSS class via a JavaScript object. The headers property is explicitly set to true. Since true is a truthy value in JavaScript, the headers CSS class gets added to the HTML element during the updating stage. As a reminder, a truthy value in JavaScript is anything other than false, 0, an empty string, null, undefined, or not a number. Those values are recognized as falsy. If a class binding value is falsy, the CSS class does not get added to the HTML element. Now, imagine that sometimes you want the growler text to be a different color. For example, right now, the appName is black by default, but once Growler connects to the web service that powers this pretend beer search engine, we apply an accent color, effectively communicating that the app is online. While this example is somewhat contrived, the code would look something like this. This is a bit more interesting than explicitly setting the property value to something truthy or falsy. Now, anytime the isOnline property changes, the UI will automatically reflect the change. So if I go to the app, open the console window, and set the isOnline property to a truthy value, you'll see that the accent color is applied. If I change the isOnline property to a falsy value, the accent color is removed from the Growler text. That's how you can get CSS classes from an object. You also saw how to get CSS classes via an array. You also saw how to bind to specific CSS properties. All of this was made possible with the power of directives. In the next section, I'd like to show you how to take your data bindings to the next level with JavaScript expressions.
Using JavaScript Expressions
Vue lets you use the full power of JavaScript expressions in your bindings. If you've work with JavaScript, or any other language for a while, it can be easy to forget some language-specific terminology. For that reason, this section will begin by defining exactly what a JavaScript expression is. From there, I'll show you how to use JavaScript expressions in your templates. You've probably seen JavaScript that looks like this. This line of code determines if the current page is running on the local machine. You might use something like this if you're trying to test something during development, but don't want it to appear in a production environment. Regardless of the situation, this line of JavaScript is known as a statement. An expression is a type of statement. A JavaScript expression is a line of code that produces a value. For example, an expression is something like this. Notice this line doesn't assign a value to a variable like the previous statement. Instead, when executed, this line evaluates to true or false. This is important, because only expressions can be used in bindings. They can also be used in the context of a template. To use a JavaScript expression in a template, just use double curly braces or mustaches. In case you're wondering, yes, we've already used JavaScript expressions in this module. I wanted to deliver some practical examples before getting to the technical details. Now that you've seen expressions in action, though, I'd like to take a moment and go a little deeper. Expressions are evaluated within the context of a view. When evaluated, an expression is scoped to the hosting view instance. To demonstrate, let's look at a real-world example of an expression in action. This example uses an expression to determine the color of the header. The expression uses the isOnline property in the data scope to make that decision. If the app is online, the header will be orange. If the app is offline, the header will be black. This is a little different than the bindings used earlier in this module. With this approach, a style is applied conditionally at runtime. If the isOnline property value changes, the expression will be reevaluated. It's not only evaluated within the context of the view instance itself, though, it's also evaluated within a sandbox. Expressions run within a sandbox. This means that they're executed in an isolated environment. This environment supports some core JavaScript properties, functions, and objects. In fact, the complete list of white-listed globals is presented on this slide. You can print this slide off if you'd like a reference card. Still, you shouldn't use user-defined global variables in an expression. Global variables that are white-listed, can't be used in expressions. This means that global variables, like the popular dollar sign in jQuery, can't be used in Vue expressions. The reason why is because these global variables may conflict with Vue itself. There is also not a way to whitelist global variables, but if you run into a situation where you need to use a global variable, you can in the context of a user-defined method. I'll be showing you how to do that later in this course. For now, I'd like to share that we've completed this module. You saw how to use JavaScript expressions in a template. In this module, you also saw how to bind to HTML attributes in content. You also saw how to set up the data schema used when creating a template. All of this information is incredibly valuable when you're displaying some data. At this point, you might be wondering how to actually collect data. That's actually the topic of the next module.
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
The trim modifier automatically removes whitespace added while input. This modifier removes both leading and trailing whitespace. This includes spaces, tabs, and line breaks. To use the trim modifier, append a .trim to the model directive, like this. This line of code will take the search phrase input by a user and remove any whitespace. Under the covers, Vue uses JavaScript's standard trim method to remove the whitespace. Once the whitespace has been removed, the modified search phrase is set to the query property in the Vue's data. As you can imagine, removing whitespace from strings at runtime can be really handy. Sometimes, though, it can be just as handy to convert input values to numbers.
Using the Number Modifier
The number modifier automatically tries to cast user input to a number. This modifier is helpful, because HTML input elements always return values as strings. This modifier tries to get a number object for you. To use the number modifier, just append .number to the model directive, like this. This line of code will take a value input by a user, and try to cast it to a floating-point number. This attempt will be performed by JavaScript's built-in parseFloat function. The reason why is because when Vue sees the number modifier, it passes the value to the parseFloat function. That means that the property in your data model will either be a number or a string. The property in your data model will be a number if at least the first character in the input value is a number. It should be noted that the leading and trailing whitespace is ignored. For that reason, you don't have to worry about using a trim modifier with the number modifier. Still, if the leading character can't be identified as a number, the leading value will be interpreted as a string. That's all there is to using the number modifier. You also saw how to use the trim modifier. These two modifiers can be very helpful when using input bindings. As of the time of writing this course, there wasn't a way to create custom modifiers, however, there is one other modifier that was available. That modifier lets you lazily bind values.
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
As users interact with an app, they expect certain things to happen when they do certain things. For example, in Growler, if a user clicked the search button, they would expect a search to run. To meet this expectation, you need to first attach to an event. V-on directive empowers you to attach to events. The on-directive listens for events in the HTML DOM. For example, here's a line of code from Growler that wires up an event handler for the Search button. In this example, I'm using the on directive to attach to the button's click event. This event is referenced after the colon separating the directive and event name. Technically, this could be any HTML DOM event supported by the hosting element. In this case, though, I'm using the click event. This approach breaks from the traditional HTML event wire-up convention. In traditional HTML, the term onClick would have been used instead of the term click, but in this context we're effectively working in the JavaScript world. For that reason, the event name that I've selected is the same name that I would have used with JavaScript's baked-in add event listener function. As a general rule, when using the on directive, ignore the on prefix that you might have used in HTML. Still, when the event specified in the on directive is triggered, some custom JavaScript can be run. In this example, that custom JavaScript gets run when the Search button is clicked. That JavaScript is this executeSearch. While there's nothing particularly interesting here, it does raise the question, what is executeSearch?
Defining Event Handlers
In this example, executeSearch is the name of a JavaScript function. Technically, this could be a JavaScript expression, but in this case I'm using a JavaScript function. This isn't some random function defined in JavaScript's global scope, though. Instead, this function must be defined within the scope of the view. To do that, you must set up the methods option. On this slide, I've moved the button definition to the right side. Here on the left side, you can once again see the growler definition. The data object was discussed in a previous module. In addition to the data object, though, another JavaScript object named methods has been added. As you can see, I separated the data and methods objects with a comma. Inside of methods, I've defined the executeSearch function. This function is defined using JavaScript's object method syntax. My guess is that this is why they call the object methods instead of functions, just a thought. Anyways, if you look at the two sides, you can see what is going to happen. If a user clicks the Search button, the query will appear in an alert box. The button in the HTML templates uses the on directive to create the bridge between the UI and functional code. The functional code shows the query entered by the user by leveraging this. In a method, the this keyword is automatically bound to the Vue instance. Since the query input's value is bound to the query property in the data object, this.query maps to what a user enters. Beyond the Vue instance content, you also have access to the event that triggered the event handler.
Examining Events and Passing Parameters
If you need to examine the event that was triggered, you can include an optional event parameter like this. In this snippet, I'm showing two things in the alert window. First, I'm showing the query that was entered by the user. Second, I'm showing the text of the button that was clicked. This text was retrieved through the event parameter. I named this parameter event just to be verbose. Technically, you can name it anything you want. The main thing is the last parameter in an event handler is the event object that triggered the event. This brings us to the next question. How do you pass other parameters to a method? To pass parameters to a method, you need to use an inline JavaScript statement. This means that you have to expand the event reference in your on directive a bit. For example, if the Growler search engine was running on a web server, you might assign a token to the user. You might want to pass that token to an event handler. To do that, you could expand the event reference like this. In this example, I'm showing a token along with the query and button text in an alert prompt. There are two things I want to discuss in this example. First is the token parameter itself, then the event variable. The token parameter is just a string that gets passed to the executeSearch function. This could have been a string, number, date, or any other JavaScript object. The samples provided with this course show each of these types being used as parameters. Those samples can be found here. Still, I used a string for the token in this sample. In addition, I'm also passing in an event variable. The event variable is a reserve variable in Vue. This variable will give you access to the HTML DOM event that was triggered. This provides the same event object that was shown just a moment ago. The only difference is that in this scenario we're passing it to the event handler with another parameter. That's really all there is to passing parameters to an event handler, and that's really all there is to cover in regards to using event handlers. As a side note, the on directive also has a shorthand syntax. That syntax uses the @ symbol as a convenience. I won't be using the shorthand syntax in this course, though. The reason why is because I prefer the more verbose syntax for the on directive. I also believe the verbose approach makes it easier to learn the content. If you have a different opinion, please let me know on Facebook. Either way, now that you know how to use event handlers, you might want to go deeper and learn about event modifiers.
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
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
The prevent modifier lets you bypass the default event behavior of an element. This modifier serves as Vue's representation of JavaScript's built-in preventDefault method. At first glance, you may wonder, why would you want to ignore an element's default event behavior. Let's revisit the Search button. In this example, I've changed the Search button a bit. Instead of it being a traditional button, I've made it an HTML submit button. Now, the default behavior of an HTML submit button is to submit form data to a server. This causes a round trip to a server, and back to the user's browser. In other words, it causes the page to reload. In a lot of cases this is fine, but what if the user did not enter a search query. If the user didn't enter a search query, we'd be doing a round trip for no good reason. This would reload the page, creating a less than desirable experience for the user. It would also take up a few more computing cycles on the server. To improve the search experience, we should validate the data as much as we can on the client side before sending it to the web server. To do that, you can use the prevent modifier like this. In this example, I've added the prevent modifier to the submit search button. Once this button is clicked, the executeSearch function will run. This function's purpose is to validate the user input. If the user entered a search query, the form will be submitted. Otherwise, this code will alert the user to their mistake. The prevent modifier prevents the form from being submitted unless it passes validation. While the prevent modifier prevents the default event behavior, it doesn't prevent event propagation. To address that, you need the stop modifier.
Using the Stop Modifier
The stop modifier can be used to cease event propagation. This modifier serves as a convenient hook to JavaScript's built-in stopPropagation method. If I revisit the Search button example and apply the stop modifier to the Search button, I'd get this. This modifier significantly changes the behavior we've recently seen due to propagation. With the stop modifier in place, only the executeSearch method would run, nothing else. To further demonstrate the stop modifier's behavior, I'm going to move it up the visual tree. Notice how I moved the stop modifier to the parent element. Now, on this slide, the executesearch method would run, and then the parentClick handler. However, that's as far as the event would propagate. The grandparentClick would not get run if the search button was clicked. I specifically chose this example to show you that there is a way to cease propagation. I find stopping propagation to be really useful. In Growler, if I click the Search button, I honestly wouldn't want the event to propagate. There are two reasons why I wouldn't want this to happen. First, by stopping the propagation, less code will get executed. This may improve the performance of an app, depending on your code. Second, the stop modifier helps you create more predictable code. I know what I expect to run, and that's it, fewer side effects. In some scenarios, though, I may want to narrow what triggers an element's event handler.
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
Earlier in this module, I showed you how to attach two events. Imaging using an event handler to respond to the keys pressed by a user. For example, a common example is to perform an action when a user presses the Enter key. To handle this situation, you could do something like this. Typically, the Enter key submits a form by default, but in this example, I'm submitting the form through my view. Once again, this allows me to do some client-side validation before sending the data to the server. I'm doing this by using the keypress event to see if the Enter key was pressed. If the Enter key is pressed, a keyCode of 13 will be shared. That 13 is a bit of a magic number. Magic numbers are bad because they're difficult to remember and don't describe the intent. In addition, this line to get that 13 is a bit odd. I'll explain it in a second. Either way, there should be a simpler, more intentional way to handle this common scenario. Vue does, in fact, provide a way to handle common key events. Vue provides nine modifiers to handle common key events. These nine modifiers are for the Enter, Tab, Delete, Escape, Space, Up, Down, Left, and Right keys. When any of these keys are pressed, a key code is passed to the event handler. If you've worked with key codes in JavaScript before, these may look familiar. You may also be aware that the keyCode property used to reference these codes in JavaScript is now deprecated. Moving forward, the code property will be used to reference these codes. The problem is, as of the time of writing this course, some of the latest browser versions didn't support the code property. It also means that using key codes can introduce complexity or problems in your app. To protect your app from this issue, you can use these modifiers. Personally, I find using these modifiers just easier to use. They let you focus on your app's goals, instead of the low-level details of key codes. They're also just easier to remember. If I revisit the Enter key scenario I showed earlier, the example could be changed from this to this. With this approach, we're able to remove the checkForEnter method needed earlier. Instead, the enter modifier is now used on the keyup event of the input field. This example also shows that you can use multiple methods for a given event. I'm using one method for when the Enter key is pressed. I'm then using another method to handle any other key being pressed. With this code, if the Enter key is pressed, the evaluateKey method will be called first, because it comes first in the list. Then, the executeSearch method will be called. This shows that the order in which you reference event handlers matters. For events beyond the nine baked-in modifiers, you may want to create your own key modifiers.
Creating Key Modifiers
Vue lets you create key modifiers for key codes that are used less often. This can be useful if your app needs to support specific shortcuts via keys. For example, in Growler, it would be nice to show information about the app if a user pressed F1. To handle the user pressing F1, you would first have to define the modifier. You can define key modifiers in Vue by using the globally-visible config property. This property exposes Vue configuration details like keyCodes. To define a key modifier, you add a key value pair to the keyCodes property, like this. This example adds a key modifier to handle the F1 key. The F1 in this case, will be used as the modifier in the code. This property's value is the value that would be returned from the JavaScript keyboard event objects code, or keyCode property. Once you've defined a modifier, you can use it in your view. To use a custom key modifier, you use the name of the property you added to the keyCode's configuration. Since F1 was just added, it can be used as a key modifier, like this. In this example, I'm using the f1 modifier that was defined on the previous slide. As you can see, the f1 modifier is used, just like the other modifiers that have been shown. That's really all there is to reacting to keys pressed by a user. Believe it or not, there's also a way to react to events that come from mouse buttons as well.
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
As apps grow in size, they can take longer to load. In this situation, you should strive to create a great loading experience in your app. You can do this by rendering elements after they've loaded. This can be useful if your app is coming from a slower network connection, or if you need to wait for additional JavaScript object initialization. To demonstrate what a poor experience could look like, I've created an example which looks like this. This example is part of the sample repo that's part of this course. That repo can be found here. Still, in this example, the load of Growler is intentionally delayed by 3 seconds. This is to simulate a slow network connection. Notice how the area on the left shows the binding syntax. This happens because nothing is hiding the content while the Growler view is being created. If a user sees this, they may think that the app is broken. However, the area on the right is a bit cleaner. The user doesn't see anything until Growler has been created. This is made possible by the cloak directive. The cloak directive hides elements until a view is compiled. In module 1, we discussed that compilation happens right after a view has been created. To use the cloak directive, you add it to an element, like this. As you can see, I simply added the cloak directive to the header element. You can probably imagine that cloak can be used with a loading indicator in an app. Still, you should probably be aware that you can't just apply the cloak directive to hide content while an app is loading. In fact, to actually hide content, you must also include this CSS in your app. This CSS sets the display property of an element that includes the cloak directive. I typically place this CSS definition in a shared CSS file so that it's widely available in my app. In fact, this CSS definition is in the public/css/app.css file in the sample repo for this project. If you look at it, you'd see the code above, which sets the display property to none. The none value on the display property hides the element, however, this property value doesn't impact layout, it only impacts the visibility. This behavior helps prevent a jerky experience when an app is transitioning from the loading state to the running state. Once your app is running, you may want to conditionally show and hide elements at runtime.
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
In some situations, you know the exact number of times that you want to loop. For example, in Growler, we know the number of pages of search results that are returned by a search. This information, and the for directive, could be used to create a search results pager like this. In this code snippet, I'm using an HTML unordered list to house a list of pages. Notice that the for directive isn't placed on the ul tag, though. Instead, I've placed it on the list item element, because that's the element that needs to be repeated. This template will repeat until the limit is reached. In total, the number of list item elements created will match pageCount. That's because when looping to a number, like pageCount, Vue automatically iterates by an interval of 1. Notably, the alias itself also starts at 1. The alias is a variable used in the context before a directive. This variable represents the current item that's being iterated on. When looping through a range of numbers, like in our paging example, this value starts at 1. This may surprise you if you've worked with other programming languages. In other languages, this value would likely start at 0, however, when working with numbers, Vue automatically starts this value at 1, not 0. This lets you bind the page alias in the template to get what you want. Next to the alias is a delimiter called in. The delimiter helps make the for directive more readable. In this case, the delimiter is the word in, however, you have the choice to use the term of instead. The decision to choose in or of comes down to personal preference. The reason that of is an option is because of is more consistent with JavaScript's iterator syntax. Either way, we'll be using the in delimiter in this course. To the right of the delimiter is the source data. The source is what's being iterated over. You can iterate over a range of integers, however, you cannot iterate over a range of floating-point numbers. You can only use whole integer values in a for directive when looping a specific number of times. If you try to use a floating-point number, you'll get an error in your view. For that reason, when you need to loop a specific number of times, you need to use integers. The for directive is useful for other scenarios, though, including traversing object properties.
Traversing Object Properties
The for directive can be used to traverse object properties. The cool thing is, you don't even have to use a different syntax. In fact, if you use a JavaScript object as the source for a for directive, like this, you'll get a list of the property values in the object. In this example, each property value of currentUser would appear as a list item in the view, meaning this HTML would get rendered like this. From this rendering, you can see that if a property is a string or a number, the value simply appears, however, if a property is an array or another object, it will be rendered in a string representation. Using a for directive to get property values is pretty straightforward. You can also use the for directive to get the property names. To get each property's name and value, you can loop through an object like this. If you look closely at the for directive, you'll notice that I added the k parameter. This parameter represents the key or property name for the current property. So if this code were rendered, you'd see this. The for directive's flexibility doesn't stop there, though. You can also get the current index while looping. In this example, I've added the i parameter to the for directive. This parameter represents the current iteration index. With each iteration, I'm using the value, key, and index of each property. Now, if this view was rendered, you'd actually see all three of these components as shown on the screen. While not surprising, there is an interesting detail here. Earlier, while showing the for directive loop a specific number of times, I mentioned that the alias starts at 1. Here on the screen, though, you can see that 0 is shown. The reason for this is because when looping over a range, the alias starts at 1. This is just a nice little thing that Vue does. But in the context of properties, the alias starts at 0, not 1. This is consistent with many programming languages, including JavaScript. There is one detail that is not consistent across JavaScript engine implementations, though. To iterate over an object, Vue gets the list of keys using the JavaScript Object.keys function. This function returns an array of innumerable properties in a JavaScript object. I'm mentioning this, because different JavaScript engines return these properties in different orders. For that reason, if you need to list the properties in a consistent order, you will need to create the array of properties yourself. In either case, the for directive can be helpful when you're traversing object properties. It can also be helpful when iterating through arrays.
Iterating Through Arrays
You can use the for directive to iterate through JavaScript arrays. You can iterate over arrays of values, arrays of objects, and even arrays of arrays. To demonstrate, let's assume in Growler that we wanted to create the search results pager. This time, though, the number of pages aren't in a numeric property, like this, instead, they'll be created in an array like this. This slide shows a pre-defined JavaScript array called pages. The HTML template loops through the array and creates a list item with a link for each page. This for directive syntax has already been shown several times, however, this time we're iterating through an array of values. If we wanted to loop through an array of objects, we could by doing some like this. In this example, we're creating the pager by using an array of objects called pages. Each object in this array contains a number and a URL. These two properties are bound in the template during rendering. In this case, we're using the attribute binding syntax and the semantic binding approach described in module 2. In some situations, you may want the index of the current item in the array. You could get that index using an approach similar to the one used earlier, like this. In this example, I've added the indexer parameter i. Beyond that, everything else is the same. While you've seen the indexer approach, you haven't seen how to iterate through nested arrays. Let's pretend that each page object in our pages array has a property called sections. This property may be used to divide a result page into multiple groups. This updated array may look something like this. On this slide, I'm looping through each page in pages using the for directive again. While working with each page, though, I also loop through the nested array named sections using an inner for directive. In my semantic binding, I'm referencing data from the outer for directive here, and data from the inner for directive here. When items are associated with groups, you often need to use conditional logic, which raises the question, what happens if an element uses both an if directive and a for directive?
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
In module 2, I explained how templates can automatically react to property changes. This is possible due to the change notification and dependency tracking features that happen behind the scenes. However, I also mentioned that these features do not automatically happen on native JavaScript arrays. Instead, you must use a different approach if an array changes or is replaced. When an array changes, it mutates. Vue has seven baked-in mutation functions to change an array as needed. These seven functions are sort, reverse, push, pop, shift, unshift, and splice. Each of these functions are wrappers around the standard JavaScript array functions of the same names. The reason these wrapper functions are needed is to trigger Vue updates. If you're unfamiliar with these functions, don't worry, I'm going to go through each of them. If you are familiar with these JavaScript functions, I encourage you to at least watch the first one, so you can see the syntax used in Vue.
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
Up to this point, I've shown you how to update an array using a variety of mutations functions, however, in some situations you may want to update an individual item in an array. For example, we've been changing a list of beers. Now, imagine that in this array we discovered that the Ahool Ale wasn't just an ale. Instead, we learned that it should be a pale ale. In that case, we could update the Ahool Ale item like this. In this snippet, I'm using a function that's baked in to view. This utility function is necessary, because Vue cannot detect updates to individual array elements. This is due to the limitations of JavaScript explained at the start of module 2. Still, Vue provides a utility function named set to help you get past this limitation. In this example, the first parameter is the array that's getting updated. The second parameter is the index of the item in the array that we want to update. Finally, the third parameter is the new value. When executed, this line tells Vue to update the UI. This will result in the following. If you prefer to stay closer to JavaScript APIs, you can by using the splice function. If you prefer to use the splice approach, this example becomes this. Everything on this slide is the same, except for the code used to update the Ahool Pale Ale. This line of code is exactly one character longer than vue.set approach. For that reason, it's a marginal change if you prefer to use splice over the vue.set function. There's no difference here, it comes down to personal preference. Still, that's how you can update an array element. You also saw how to add and remove elements from an array. You also saw how to rearrange arrays with the sort and reverse options. This module was about more than that, though. In this module, you learned how to handle array changes. This is important because arrays are often the data source for lists of items in a view. For that reason, you also saw how to render lists of items. In addition, you learned how to conditionally render elements. While these features help you display exactly what you want, there are ways to do it even better. In the next module, I'm going to show you how to react to data changes to get even better performance in your view.
Reacting to Data Changes with Filters, Computed Properties, and Watchers
Introduction
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'
I want to focus specifically on the watch option in this definition. If you focus on it, you can see that the behavior of the watcher is defined in a JavaScript function. In this case, a basic function is used that calls the updateSubTotal function. Technically, since this is all this watcher is doing, it could be simplified like this. In this example, the updateSubTotal function is called whenever the shopping cart is updated. When updated, Vue looks for the function named updateSubTotal in the methods option. At this point, you may be wondering why you would want to associate a full-blown function with a watcher. The approach on this slide is clearly more compact. Well, there is an added benefit to using a function. To demonstrate, I want to show you another example. In this example, I've defined a watcher on the subTotal property. Notice that in this watcher I've passed two parameters into the watcher function. When Vue calls a watcher function, it automatically passes in two parameters. I've named those parameters latest and original, in this case. Technically, you could give these parameters any valid name you wanted to. Still, what's important is what they represent. The first value is the value that the data property has been changed to. In this example, the latest parameter would be the value of the Subtotal including an added beer. However, the original parameter would be the value of the Subtotal before the price of the new beer is included. This is a way of inspecting the before and after state of a watched property. At this point, you may want to know why I chose to use the subTotal property instead of the shopping cart property used earlier. The fact is, I could not use the shopping cart property to show the latest and original parameter usage. The reason why is because Vue doesn't keep data copies for objects and arrays. Since the shopping cart is an array, it wouldn't work. Instead, you would need to use an expression like this to detect a change in the length of an array. This example watches for changes to the length of the shopping cart. If a beer is added or removed from the array, the subTotal will get updated. While this is useful for handling changes to the length of an array, sometimes the contents of an item within an array, changes. To track those types of changes, you need to go deeper. In fact, you need to define a watcher's depth.
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.
Defining Filters
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
While you can call filters decoratively, you can also call them programmatically. Once your view has been instantiated, the filters object becomes available via the options property. This means that you can access your filters via JavaScript. For example, if you wanted to refactor the convertIBU filter into multiple filters, you could. In fact, let's pretend that you decided to refactor the convertIBU filter like this. This slide shows the convertIBU filter refactored. Now, instead of one single filter, there are actually three. It should be noted that all of these filters belong in the filters object discussed earlier. I'm showing them this way due to the available real estate on the screen. You can see the actual implementation in the sample repo that goes with this course. Still, the convertIBU filter shown in the left half is calling the removePeriods and toUpperCase filters defined in the right half. I want to point out this check right here. This assertion is used to ensure that Growler is defined. The reason for this is because filters are added to the options after instantiation. Without this check, the app would not work. Still, once available, I can programmatically call each of the filters as shown on the screen. In reality, though, you shouldn't do this. I did this for the sole purpose of showing you the syntax of how to programmatically call a filter from another filter. Instead, you should consider chaining filters together.
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.