Iterating over Objects
When requesting data from an API, you will often be iterating over an array of objects that contains both logic and raw content. Vue makes it easy to control the data's various states through its directive syntax. Conditional directives control the display state of DOM elements in Vue. The HTML syntax provides clear visibility when it comes to the display rules set in your component.
Exercise 1.09: Using a v-for Loop over an Array of Objects and Using Their Properties for v-if Conditions
In this exercise, we will be controlling a Vue data array and iterating over the objects inside of it.
To access the code files for this exercise, refer to https://packt.live/32YokKa.
- Open a command-line terminal, navigate into the
Exercise1.09
folder, and run the following commands in order:> cd Exercise1.09/ > code . > yarn > yarn serve
Go to
https://localhost:8080
. - Compose the following syntax inside
Exercise1-09.vue
and create a data object that contains atitle
string, and afavorite
array of strings. We will loop over theinterests
object similarly to the array of strings; however, you will need to refer to thetitle
key inside theinterests
object:<template> <div> <h1>Looping through array of objects</h1> <ul> <li v-for="(item, n) in interests" :key="n"> {{ item.title }} </li> </ul> </div> </template>
The output of the preceding code will be as follows:
- Let's create a second
v-for
loop to iterate over your favorites list. Note that we use different keys—fav
andm
—for our nested loop. This is because you can still use the valuesitem
andn
inside the nested loop context:<template> <div> <h1>Looping through array of objects</h1> <ul> <li v-for="(item, n) in interests" :key="n"> {{ item.title }} <ol> <li v-for="(fav, m) in item.favorite" :key="m"> {{ fav }}</li> </ol> </li> </ul> </div> </template>
Figure 1.29 displays an output where looping is performed through an array of objects:
- To optimize the DOM tree, we can use the
v-if
conditional directive fromExercise 1.09
to hide unnecessary DOM elements: - We will check whether there are more than
0
items in the array to display the ordered list HTML element. Add av-if
directive to the<ol>
with the conditionitem.favorite.length > 0
:// src/components/Exercise1-09.vue <template> <div> <h1>Looping through array of objects</h1> <ul> <li v-for="(item, n) in interests" :key="n"> {{ item.title }} <ol v-if="item.favorite.length > 0"> <li v-for="(fav, m) in item.favorite" :key="m"> {{ fav }}</li> </ol> </li> </ul> </div> </template>
This won't make a difference in the visuals of your page, but when you inspect the virtual DOM tree in your browser, you'll notice an HTML comment in dev mode allowing you to understand where a
v-if
statement might befalse
. When you build for production, these HTML comments won't be in your DOM.
By using the v-if
directive in dev mode, you will see an HTML comment. These will not exist in production builds.
In this exercise we have been able to iterate over complex arrays of objects, outputting these objects' nested keys and controlling the view state of DOM elements based on length conditions.
Methods in Vue
Vue methods are defined inside the methods
object within the Vue instance and can be written like normal JavaScript functions where you define a piece of logic that is executed. When you use JavaScript functions, normally, you would either return a value or simply perform a global action. The primary difference between writing functions and Vue methods is that the Vue method is scoped to your Vue component and can be run from anywhere inside the component it was written inside. Since the methods are scoped to your component's Vue instance, you can reference them inside of event directives easily in the HTML template. When binding events to HTML elements in Vue, you would use the @
symbol; for example, v-on:click
is equivalent to @click
.
Exercise 1.10: Triggering Methods
In this exercise, we are going to build a component that uses Vue's methods API. Consider how similar these Vue methods can be written like your own named functions in JavaScript, as they behave in a very similar way. By the end of the exercise, we should be able to use methods and trigger them from the HTML template.
To access the code files for this exercise, refer to https://packt.live/3kMTWs5.
- Open a command-line terminal and navigate into the
Exercise1.10
folder and run the following commands in order:> cd Exercise1.10/ > code . > yarn > yarn serve
Go to
https://localhost:8080
. - Let's loop over a method trigger and pass its number to a method. Set up an anonymous
v-for
loop on an HTML list and add an anchor element inside of the list element. Set the loop to iterate5
times:<template> <div> <h1>Triggering Vue Methods</h1> <ul> <li v-for="n in 5" :key="n"> <a href="#">Trigger</a> </li> </ul> </div> </template>
- Add the
@click
directive referencing a method calledtriggerAlert
and pass the value ofn
as an argument. Output the valuen
into the anchor element using curly braces:<template> <div> <h1>Triggering Vue Methods</h1> <ul> <li v-for="n in 5" :key="n"> <a href="#" @click="triggerAlert(n)">Trigger {{ n }}</a> </li> </ul> </div> </template>
- Inside the
methods
object, add thetriggerAlert(n)
key with then
argument. Inside this method, add analert
function, which will output the valuen
plus some static text:<script> export default { methods: { triggerAlert(n) { alert(`${n} has been clicked`) }, }, } </script>
- Add styling inside the
<style>
tag at the bottom of the component, and set thelang
attribute toscss
:Exercise1-10.vue
22 <style lang="scss" scoped> 23 ul { 24 padding-left: 0; 25 } 26 li { 27 display: block; 28 list-style: none; 29 30 + li { 31 margin-top: 10px; 32 } 33 } 34 35 a { 36 display: inline-block; 37 background: #4fc08d; 38 border-radius: 10px; 39 color: white; 40 padding: 10px 20px; 41 text-decoration: none; 42 } 43 </style>
The complete code for this step is available at https://packt.live/374yKZZ.
- Your page should feature a list of buttons that when clicked, trigger an alert with a message that contains the button number you clicked as follows:
The following prompt is displayed when a trigger is clicked:
Note
While you can add an event directive to any HTML element, a suggestion would be applying them to native HTML interactive elements such as anchor tags, form input, or buttons to help with browser accessibility.
In this exercise, we were able to utilize the Vue methods API to define and trigger methods from the HTML template, and parse arguments into each method dynamically.
Exercise 1.11: Returning Data Using Vue Methods
In this exercise, we are going to learn how to use Vue methods as a function to return data in the Vue instance and inside of the template.
Often in a web application, we want elements to appear on the page depending on whether a condition is met or not. For instance, if our product is not in stock, our page should display the fact that it is out of stock.
So, let's figure out how could we conditionally render these elements, depending on whether our product is in stock or not.
To access the code files for this exercise, refer to https://packt.live/3pHWCeh.
- Open a command-line terminal, navigate into the
Exercise1.11
folder, and run the following commands in order:> cd Exercise1.11/ > code . > yarn > yarn serve
Go to
https://localhost:8080
. - Let's iterate over a random amount and trigger an
addToCart
method. Set up two data objects,totalItems
andtotalCost
, which will be updated when a user clicks on our shop buttons. Next, refer to data objects inside thescript
block of Vue by specifyingthis
. For example, in thetemplate
block, we refer tototalItems
as{{ totalItems }}
, but in thescript
block, we will refer to it asthis.totalItems
. The same pattern is used for methods whereaddToCart
would be referred to asthis.addToCart
within another method:<template> <div> <h1>Returning Methods</h1> <div>Cart({{ totalItems }}) {{ totalCost }} </div> <ul> <li v-for="n in 5" :key="n"> <a href="#" @click="addToCart(n)">Add {{ n }}</a> </li> </ul> </div> </template> <script> export default { data() { return { totalItems: 0, totalCost: 0, } }, methods: { addToCart(n) { this.totalItems = this.totalItems + 1 this.totalCost = this.totalCost + n }, }, } </script> <style lang="scss" scoped> ul { padding-left: 0; } li { display: block; list-style: none; + li { margin-top: 10px; } } a { display: inline-block; background: rgb(235, 50, 50); border-radius: 10px; color: white; padding: 10px 20px; text-decoration: none; } </style>
This will generate an output as follows:
When you click the buttons, the items counter should increment by
1
, but the cost will increment by then
value, which should demonstrate normal cart functionality (clickingAdd 2
, thenAdd 5
): - Let's talk money. We can use methods to perform logical operations that augment or format strings based on events. Create a method called
formatCurrency
, which accepts one argument. We will return the same value after giving it two decimal points and a$
symbol. To use this method in the template, simply add it to the interpolated curly braces and pass the value that was there as an argument inside the method instead:<template> <div> <h1>Returning Methods</h1> <div>Cart({{ totalItems }}) {{ formatCurrency(totalCost) }} </div> <ul> <li v-for="n in 5" :key="n"> <a href="#" @click="addToCart(n)">Add {{ formatCurrency(n) }}</a> </li> </ul> </div> </template> <script> export default { data() { return { totalItems: 0, totalCost: 0, } }, methods: { addToCart(n) { this.totalItems = this.totalItems + 1 this.totalCost = this.totalCost + n }, formatCurrency(val) { return `$${val.toFixed(2)}` }, }, } </script>
The following screenshot displays the output of the preceding code:
In this exercise, we were able to utilize Vue's methods API to parse arguments into methods, return modified values, and use methods to update the local data state in a life-like scenario.