Instantiation, Callbacks, and template syntax with Vue.js part 2 of 3.
In the previous article of this Vue series, feet got wet and basics were covered that would enable a user to get started with exploring what Vue.js could do. That was a simpler time, when you were allowed to enjoy such innocent pleasures. But that kind of innocence only lasts so long before you find yourself scraping to understand why the code on line 27 is throwing a Uncaught TypeError: Cannot read property of undefined
. And you know what is really scary? StackOverflow may not be there to hold your hand through it all.
So today we are going to dive deeper into how a new instance of Vue.js gets bootstrapped into the DOM and what lifecycle hooks are available to you during that instantiation process. Then we will dig in to the template syntax that Vue.js leverages. At the end of this article you should have a pretty good understanding of how Vue.js attaches itself to the DOM and how it renders content within the HTML document of your project.
The previous article demonstrated several very simple apps, in each of which I instantiated a new Vue.js instance to handle the functionality I wanted to create. Within a production sized application, it likely doesn’t make sense to instantiate new Vue.js objects all over the page, instead favoring composing the app of several Vue components. We will explore how to accomplish this composability within Vue.js at a later point. For now we will favor understanding what arguments are necessary to create our shiny new Vue instance. Keeping it simple, a new Vue.js instance really only requires a JSON object with two key-value pairs; el and data. The value assigned to el could really be any element within your HTML document (excepting the html, head, and body tags), including a class name, but it is important to know that the Vue app you instantiate will only attach itself to the first element in your document whose class name matches what you provided to your Vue instance. Best practice is to provide the el key in the instantiation JSON object with an id from the DOM, like so:
<div id='myAmazingVueApp'></div>
<script>
var app = new Vue({
el: '#myAmazingVueApp'
})
</script>
The value provided to the data key is itself another object with key-value pairs. These are the custom properties defined by you on your Vue instance and they are Reactive according to the Vue.js documentation. This simply means that if these properties are being used by the DOM, as the values to these properties dynamically change within the Vue.js instance as a result of an AJAX call or a user interaction, the DOM will reflect those changes, rerendering the view with the new values. For example:
<div id='myMediocreApp'>
<p>This is some { { amazingText } }</p>
</div>
<script>
var app = new Vue({
el: '#myMediocreApp',
data: {
amazingText: 'truly amazing text!'
}
})
</script>
When the page renders, the text “This is some truly amazing text!” will display on the screen. However, if you open the web inspector console, type app.amazingText = 'not really great text'
, you will see the view immediately rerender and the message on the page will instead read “This is some not really great text”.
So properties within the data attribute of my Vue instance are tied to the DOM. Cool beans.
At the risk of explaining a concept that is likely very familiar to many of you, lifecycle hooks provide a way to trigger custom code execution at various points of the Vue.js instance’s lifecycle. What’s a practical example of this? Well let’s say that your Vue.js instance requires some data from an external server and you want to make an AJAX call to retrieve that data so that it can be displayed on the page. It would be possible to figure out a way to trigger that call outside of the Vue.js framework, but it would be inconvenient and likely pretty hacky, just like an axe in your leg. Instead you could tap into the beforeCreate
or beforeMount
lifecycle hooks to go get that data and assign it to your instance’s properties, saving you the hassle of figuring out how to trigger that behavior yourself. The lifecycle hooks that Vue.js provides are as follows:
It is pretty easy to intuit what each of these does, save the beforeMount
and mounted
hooks, so they probably deserve a bit of explanation. beforeMount
gets called just before the Vue object gets bootstrapped to its assigned element. If you intend to mount to an element with an id of foobar then the beforeMount
code will get called before the Vue object attaches itself to the foobar element on your page. mounted
gets called after the Vue object has attached itself to the designated HTML DOM element. These lifecycle hooks get defined as methods on the Vue instance, but they are defined outside of the custom defined methods that you may need to use within your project.
var app = new Vue({
el: '#app',
data: {
message: 'Amazing Stuff Here'
},
methods: {
changeMessage: function() {
this.message = 'Amazing Stuff All gone'
}
},
created: function() {
console.log('New Vue.js instance created!');
}
})
Here you can see that I created a custom method on the Vue object called changeMessage(). However, I also defined a created
function on the Vue instance which, when the Vue framework reads, will call that function and execute the code I provide in its definition.
Lifecycle Hooks, huh? Welp, see ya later!
Now that we have a better idea of what is going on when a new Vue instance is created, and what we can do at the different points of the instance’s lifecycle, it is time to pivot a bit and talk about Vue.js’s template syntax.
As you get more and more familiar with the Vue.js framework, you will see that much has been borrowed from other frameworks, and template syntax is no exception. Data that gets exposed to the DOM can be interpolated through the use of double curly braces { { } }
, a pattern very common in other JS frameworks as well. So if I have a custom property on my view instance named userName, and in my template I include <p>Welcome back,
, I could expect to see something like “Welcome back, Kotter” rendered on my screen. So that is great for presenting data to end users, but what about attaching data to HTML element attributes? That is where the v-bind
directive provided by the Vue.js framework comes in to play. Perhaps you would like to dynamically assign an ID to an element on the page. You could accomplish that like so:
<div id='app'>
<p v-bind:id="aFancyId"></p>
</div>
<script>
var app = new Vue({
el: 'app',
data: {
aFancyId: '1dKw1tA'
}
})
</script>
The resulting DOM would show a paragraph tag with an id of “1dKw1tA”.
Of note is how Vue.js treats boolean attributes. Vue.js operates with a sense of truthy and falsy values. null
, undefined
, false
, ''
, and []
all are interpreted as false
when determining a boolean value. Most anything else gets treated as a truthy value. So here: <input v-bind:disabled="isInputDisabled"></input>
would result in the input field being disabled if isInputDisabled
is a truthy value. If isInputDisabled
is a falsy value, the input field would work as normal.
Vue.js comes with several template directives built in, but the two most common have got to be v-if
and v-on
. v-if="booleanValue"
allows for a DOM element to be conditionally displayed based on the value of booleanValue
. Once again, it is important to note that as long as the value of booleanValue
isn’t null
, undefined
, or false
, it will be interpreted as a truthy value. v-on
allows you to attach a DOM element to an event and run a custom method as a result of that interaction. For example:
<div id='app'>
<button v-on:click="alertUserOfTime">Push me for the time</button>
</div>
<script>
var app = new Vue({
el: '#app',
methods: {
alertUserOfTime: function() {
alert("12 o'clock an’ all is well!");
}
}
})
</script>
would result in displaying an alert box with the text “12 o’clock and all is well!” in it. A much more practical application of this directive would to be execute a POST request to a backend API for saving data.
Directives. They’re pretty direct!
So now you have a better idea of what is going on when a Vue.js application bootstraps its root instance, how you can, and why you might want to, tap into the power of lifecycle hooks, and how to begin leveraging template syntax to create dynamic experiences for your end users.
There is still so much left to learn, like event handling, form input bindings, and components, but that will all be in good time. Up next! Computed Properties and You. For now, play around, do something stupid, and bask in the joy of your honeymoon phase with Vue.js!