DEV Community

Marina Mosti
Marina Mosti

Posted on • Updated on

Hands-on Vue.js for Beginners (Part 7)

We are nearing the end of journey, and you are almost ready to graduate from Vue Padawan level. But first watchers, you must learn.

We're going to tackle two very important concepts today, watchers, as mentioned, and form input bindings.

Let's get started and we'll build a super simple form to showcase both these fantastic features.

<html>

<head>
  <title>Vue 101</title>
</head>

<body>
  <div id="app">
    <label>What's your favorite game ever?</label>
    <input type="text" >

    <hr>

    <p>{{ response }}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data() {
        return {
          favoriteGame: null,
          response: ''
        }
      }
    });
  </script>
</body>

</html>

Let's take a look at what we're doing here.

Inside our <div id="app"> we've created a label and the most basic form of an <input> tag. After, we're outputting the result of a response property.

Inside our Vue instance, we're declaring a local state that includes two properties, favoriteGame and response. Also note, that we're using the data() as a function with the return syntax this time, if we don't v-model won't work.

The idea here, is that we want to first be able to store whatever the user inputs on the <input> field into a variable, that way we can use it later on as we see fit.

In vanilla JS or even jQuery you may be tempted to try to capture the input element with a $('input') or document.querySelector, but in Vue we have a much simpler way to achieve this mundane task.

Introducing v-model.

v-model

As you've learned before, everything that starts with a v- is a Vue directive. What v-model in particular translates to, in very simple terms, is:


Vue, I want you to grab this input that i'm putting this v-model directive on, and make a two way relation with it. I'm going to give you a property, and whenever I change this property anywhere in my code - I want you to change it on the input, and likewise, whenever this input changes - I want you to reflect those changes in my prop.

Let's try to put this in action, go to the <input> declaration, and add the v-model directive to it.

<input type="text" v-model="favoriteGame">

Now go and run this in your browser and type something into your magical input box of goodness. Taaaaa...da?

Ok, even though nothing seems to be happening. Go ahead and open your Vue devtools and inspect the <Root> element's data. YEAH. Progress!

Now go into the dev tools and change the value of favoriteGame into something else (don't forget the quotes wrapping it, we need a string here). EZ-BINDS-R-US 💪

Vue is VERY smart about how to bind with every type of native HTML form inputs, so really you only need to drop in the v-model bomb and profit, but the power of v-model really shows when you start building your own wrapper components and using it a-la-carte.

Behind the scenes v-model is actually setting up a v-bind:value and a v-on:input even binding, but going in depth on this is a bit out of scope so i'm just going to drop you a link if you're interested in looking further and look the other way. v-model on Components

Watchers

Now that we have our sweet sweet two-way binding v-model awesomeness in place, let's actually do something with it.

You've already learned that with a state data prop you can put it in your template with {{ favoriteGame }}, so no need to go over that again. You've learned how to use it inside a method and computed prop with this.favoriteGame - so no need to redo that. But what happens when you want to "listen" or "react" to this property actually getting modified?

Computed properties are fantastic at recalculating stuff and returning a value, but what if we want to modify another piece of state on our app when this value changes, or maybe even fire an async request of some sort? In these niche cases watchers come and save the day.

Let's go an add the boilerplate for creating a watched prop.

<script>
  const app = new Vue({
    el: '#app',
    data() {
      return {
        favoriteGame: null,
        response: ''
      }
    },

    // Watchers here
    watch: {
      favoriteGame(newValue, oldValue) {
        console.log('Favorite game was ' + oldValue + ' and now is ' + newValue)
      }
    }
  });
</script>

Watchers are defined inside a watch property in our instance or component, and we pass it an object that will include a property for each one of the props we want to watch.

In simple terms, every data prop or props prop you want to watch/react to needs to go inside this watch: {} with its name. So if your prop is named favoriteGame that's the name of your function.

Each one of these functions gets two params passed to it, the first one will be the newValue that this prop is getting, and the second one is the oldValue that it used to have before the change.

Check out the console.log statement and refresh your browser window. Try typing something into the <input> and check out your console output. Every time our favoriteGame prop changes in ANY way, this watcher will be fired.

Now let's actually do something cool with it. Remember our response prop? Let's put something into it depending on what the user answers, and have some fun with it.

watch: {
  favoriteGame(newValue, oldValue) {
    if (!newValue) return // If its an empty string, pass

    // If the new value contains the keyword metroid
    if (newValue.toLowerCase().indexOf('metroid') !== -1) {
      this.response = 'Ceres station is under attack!'
      return
    }

    // If the new value contains the word zelda
    if (newValue.toLowerCase().indexOf('zelda') !== -1) {
      this.response = 'Its dangerous to go alone, take this 🗡️'
      return
    }

    // If the OLD value was metroid, and user changed it something else
    if (
      oldValue.toLowerCase().indexOf('metroid') !== -1 &&
      newValue.toLowerCase().indexOf('metroid') === -1
    ) {
      this.response = 'GET TO DA CHOPPA NAO'
      return
    }

    // Default response
    this.response = 'Sure, why not?'
  }
}

In case you don't know, indexOf checks the string and returns -1 in case there was no match, and else it returns the position of the string we're searching for in the string being searched.

Go ahead and have some fun with this, make some new examples and play with it in your browser.

I hope you can see now the power of watched properties, the way I have found it useful is to think, if my property changes and I need to REACT programmatically to it (with an ajax call, an external function, updating a secondary value, etc), then watchers are usually a good call. For anything else, go with computed properties.

<html>

<head>
  <title>Vue 101</title>
</head>

<body>
  <div id="app">
    <label>What's your favorite game ever?</label>
    <input type="text" v-model="favoriteGame">

    <hr>

    <p>{{ response }}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data() {
        return {
          favoriteGame: null,
          response: ''
        }
      },
      watch: {
        favoriteGame(newValue, oldValue) {
          if (!newValue) return

          if (newValue.toLowerCase().indexOf('metroid') !== -1) {
            this.response = 'Ceres station is under attack!'
            return
          }

          if (newValue.toLowerCase().indexOf('zelda') !== -1) {
            this.response = 'Its dangerous to go alone, take this 🗡️'
            return
          }

          if (
            oldValue.toLowerCase().indexOf('metroid') !== -1 &&
            newValue.toLowerCase().indexOf('metroid') === -1
          ) {
            this.response = 'Nothing is true , everything is permitted'
            return
          }

          this.response = 'Sure, why not?'
        }
      }
    });
  </script>
</body>

</html>

Conclusion

Congratulations on making it this far!

You now have the basic tools to actually build a really cool and functional application in Vue, I guarantee it. However, there is still a lot to learn and a lot to explore in order for you to squeeze every inch of juice out of this framework.

But don't worry, I've said it before and I stand by it today, one of the key aspects I enjoy most about Vue.js is the documentation.

I remember back when I was starting out with programming I was really afraid of having to dive docs because they were usually really poorly explained, and assumed a high level of understanding of the language and the framework/lib that I was trying to use.

Thankfully, the Vue docs team has done a wonderful job of making a complete guide full with examples for everything that we have covered in this guide plus everything else you need to excel at this framework.

This concludes the Beginner series for Vue!

If you want to keep up with my articles, keep an eye on my Twitter account at @marinamosti and check out my other articles at Progress' blog!

Beware the power of the magical avocado, and thanks for reading! ♥

Oldest comments (47)

Collapse
 
lauragift21 profile image
Gift Egwuenu

Great job with this series Marina 🙌

Collapse
 
marinamosti profile image
Marina Mosti

Thank YOU for being an inspiration to teach!

Collapse
 
lauragift21 profile image
Gift Egwuenu

No Thank you :) ❤️❤️

Collapse
 
rsmoke profile image
rsmokeUM

I have been dabbling with Vue.js for a few months now and this is the first tutorial series that really hit home with how all the basic bits dance with each other. I have recommended this series to my coworkers as a way to get started with putting "it all together"! Thanks a gazillion avocados for the time you took to put this together 🥑🥑🥑

Collapse
 
marinamosti profile image
Marina Mosti

Thanks a ton for your comment :) I had a lot of fun doing it and def this type of reply is a huge motivation!

Collapse
 
rgehrsitz profile image
robertg

Thanks for a great introduction to Vue! It was at a pace and level that was perfect for me to use and understand.
Keep up the great work!

Collapse
 
marinamosti profile image
Marina Mosti

Thank you so much for your feedback Robert, im glad you enjoyed it :)

Collapse
 
namstel profile image
Namstel

I feel like I have a good understanding of the fundamentals now. I liked how you split it all up in 7 parts with clear beginnings and endings, that somehow makes it easy for me to pick it up compared to when everything is wrapped in one article (somehow I then feel the need to finish it all in one go).

Looking forward to more of your teachings.

Collapse
 
marinamosti profile image
Marina Mosti

Thanks Namstel!!!

Collapse
 
nbsamurai profile image
Subramani Simhachalam

I've read the complete Vuejs documentation about 4 months back but didn't get time to work on the concepts. Your tutorial series served as a prefect refresher. Thanks for writing this series.

Collapse
 
marinamosti profile image
Marina Mosti

Subramani thank you for your words, i'm glad you enjoyed it!

Collapse
 
oki profile image
Oki

Thanks Marina!
i really enjoyed going through you vuejs tutorial. +10

Collapse
 
jamiemccarville profile image
Jamie McCarville 🇨🇦

Great work on this series of articles! I have also been playing around with Vue for a little bit now and this is the best set of beginner articles that I have come across. Looking forward to more Vue content from you.

Collapse
 
nickwireless profile image
Nick Hanigan

You were great on ViewsOnVue podcast and so I thought to pop over to read your lessons. Thanks all round! 🏅🏅

One vote for your next topic is $emit and how that fits with parent, child and props etc. . I'd like your take on it because was shakey on it first time around.🤗

Collapse
 
marinamosti profile image
Marina Mosti

Hey Nick! Thanks a ton for your feedback :) An article about $emit is a great idea, I will definitely take it into account :D

Collapse
 
nickwireless profile image
Nick Hanigan

😀 thanks. 👍

Collapse
 
ipas profile image
iPAS • Edited

Thank you for the great series that make me has a happy beginning on Vue.js.

Just note in case you are waiting for a curious student.
I found warnning in the console while typing first letter in the input box.
It warned me because of oldValue.toLowerCase() so that oldValue=null.
Trus, for the first time, 'Sure, why not?' will not be shown by only one input character.

Collapse
 
marinamosti profile image
Marina Mosti

Hey iPAS! Thanks for your feedback and for reading!

Collapse
 
jaymoh profile image
James Shisiah

Thank you Marina for your tutorial. As a beginner, it has helped me get the grasp on Vue.js.
Also, I tried out this bit and it worked just fine with v-model, without using the function return syntax:
data: {
favoriteGame: null,
response: ''
},

Thanks for the good work.

Collapse
 
marinamosti profile image
Marina Mosti

Hi James, thanks for your words. In components, you MUST use the function return syntax, else the state is going to get SHARED by all your components. If this is your MAIN component, App.vue, you can get away with using this syntax because you can guarantee there will only be one.

Collapse
 
jaymoh profile image
James Shisiah

You're very much welcome Marina, and thank you for clarifying this.

Collapse
 
peaceman profile image
peaceman

Thanks for all the effort you made into writing this.. It was really clear and beginner friendly.

Collapse
 
marinamosti profile image
Marina Mosti

Hey Peaceman, thanks for reading! Glad you liked it

Collapse
 
jacjames24 profile image
jacjames24

Great series!

I have been trying to delve into vue and this series has really explained it really well. Funny thing is when there are times when I have been thinking such as why sometimes data (or any other concept) is declared as a function and then as an object, right there in in the next sentence, you actually have stated the difference and the reason! :D

All-in-all, good job!

Collapse
 
marinamosti profile image
Marina Mosti

Hello James, I'm glad you like it! Stay posted to my twitter for more articles coming soon, and check out my others on Progress' blog telerik.com/blogs/author/marina-mosti

Collapse
 
robertleroy profile image
Rob

Error: Cannot read property 'toLowerCase' of null

it works with the error or changing favoriteGame: '',

Thanks for the series. Good stuff

Collapse
 
lichadc profile image
Lisandro Dalla Costa

Extremely grateful for your fantastic explanations!!!

Collapse
 
marinamosti profile image
Marina Mosti

Extremely grateful for your comments :) Check out my other articles too in telerik.com/blogs/author/marina-mosti
Especially this one to answer your other comment regarding npm and the cli telerik.com/blogs/a-first-look-at-...

Collapse
 
lichadc profile image
Lisandro Dalla Costa

Maybe I feel that still need to know more of npm, and this things to use it in a real proyect!