Categories
Vue 3

Vue 3 — Directive Shorthands and Arguments

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at the dynamic arguments of a directive.

Dynamic Arguments

Vue 3 directives can take dynamic arguments.

For example, we can write:

<a v-bind:[attributeName]="url"> ... </a>

or:

<a v-on:[eventName]="doSomething"> ... </a>

We can pass in an argument to a directive.

This applies to any directives, including the ones we create.

Modifiers

We can also pass in modifiers to a directive.

For instance, the v-on directive can take a modifier for some event.

We can write:

<form v-on:submit.prevent="onSubmit">...</form>

to let us call event.preventDefault in the onSubmit handler.

This lets us stop the default behavior from happening.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="[https://unpkg.com/vue@next](https://unpkg.com/vue@next)"></script>
  </head>
  <body>
    <div id="app">
      <form v-on:submit.prevent="onSubmit">
        <input v-model="name" />
      </form>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            name: ""
          };
        },
        methods: {
          onSubmit() {
            console.log(this.name);
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

to create a form with the v-on:submit:prevent directive to run the onSubmit method with the event.preventDefault method all in one directive.

Shorthands

We can shorten v-bind to : .

For example, we can write:

<a :href="url"> ... </a>

instead of:

<a v-bind:href="url"> ... </a>

We can also pass in an argument with the shorthand by writing:

<a :[key]="url"> ... </a>

We can use it by writing:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <a :href="url">link</a>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            url: "http://example.com"
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

v-on also has their own shorthand.

Instead of writing:

<a v-on:click="doSomething"> ... </a>

We can write:

<a @click="doSomething"> ... </a>

for short.

If we want a dynamic event, we can write:

<a @[event]="doSomething"> ... </a>

So we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <button @click="toggle">toggle</button>
      <p>{{on}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            on: true
          };
        },
        methods: {
          toggle() {
            this.on = !this.on;
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

to add a click listener to our button.

Caveats

Dynamic value has some constraints.

Whatever is inside the square brackets must return a string or null .

null can be used to remove the binding.

Any other value will trigger a warning.

Certain characters aren’t valid in HTML, so we can’t have them as the dynamic argument’s value.

So we can’t have names with spaces of quotes.

Something like:

<a v-bind:['foo ' + bar]="value"> ... </a>

won’t work.

We should also avoid naming keys with uppercase characters since browsers will convert them to lowercase.

JavaScript Expressions

Templates expressions are sandboxes so we can’t use global variables in template expressions.

It can only access the list of global variables from a whitelist.

The whitelist is at https://github.com/vuejs/vue-next/blob/master/packages/shared/src/globalsWhitelist.ts#L3.

Conclusion

Vue directives can take dynamic arguments.

Also, there’re various shorthands we can use in place of some directives.

Categories
Vue 3

Vue 3 — Computed Properties and Watchers

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at Vue computed properties and watchers.

Computed Properties

We can add computed properties to derive some from an existing property.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="message" />
      <p>{{reversedMessage}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            message: ""
          };
        },
        computed: {
          reversedMessage() {
            return this.message
              .split("")
              .reverse()
              .join("");
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

We added the message property to the object we return in data .

Then we added the computed property to the object we passed into createApp .

Methods are inside it getters, so we return things derived from other properties.

The method must be synchronous.

Now when we type in something to the input, we’ll see the reversed version displayed below it.

Computed Caching vs Methods

We can achieve the same result by running a method to reverse the string.

But it wouldn’t be cached based on their dependency if we use a regular method to return derived data.

Computed properties are cached based on the original reactive dependencies.

As long as this.message stays the same, reversedMessage won’t be run.

However, if we have dependencies that aren’t reactive in our computed property, then the method won’t run.

In this case, we’ve to use methods to make them update.

So something like:

computed: {
  now() {
    return Date.now()
  }
}

won’t update.

Computed Setter

We can have setters in our computed properties.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="firstName" placeholder="first name" />
      <input v-model="lastName" placeholder="last name" />
      <p>{{fullName}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            firstName: "",
            lastName: ""
          };
        },
        computed: {
          fullName: {
            get() {
              return `${this.firstName} ${this.lastName}`;
            },
            set(newValue) {
              const names = newValue.split(" ");
              this.firstName = names[0];
              this.lastName = names[names.length - 1];
            }
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the firstName and lastName properties in the object we return with data .

Then we can create the getter for the fullName property by returning the 2 properties combined into one string.

The setter would be the set method which takes the newValue and then split it back into its parts.

We set the this.firstName and this.lastName based on the combined string we have returned from get .

When this.firstName and this.lastName change then get is run.

If get is run, then set is run.

Watchers

Computed properties work for most cases, but sometimes we need watchers to provide us with a more generic way to watch for data changes.

For example, we can use it by writing:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="name" />
      <p>{{data}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            name: "",
            data: {}
          };
        },
        watch: {
          name(newName, oldName) {
            if (oldName !== newName) {
              this.getData(newName);
            }
          }
        },
        methods: {
          getData(newName) {
            fetch(`https://api.agify.io/?name=${newName}`)
              .then(res => res.json())
              .then(res => {
                this.data = res;
              });
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have a getData method which takes a newName parameter and get some data from an API.

And then we have our watch property, which has an object with watchers.

The name of the method would match the name of the instance property name.

A watcher takes an old value and a new value as the parameter.

And we can run what we want inside it.

The code we run is async so we got to use a watcher instead of computed properties.

Conclusion

Computed properties and watchers let us watch for reactive data changes and let us run code when they change.

Categories
Vue 3

Vue 3 — Class Bindings

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at class bindings.

Class Bindings

To let us style our app dynamically, we got to be able to set dynamic classes and styles with it.

One way to set a class is with th object syntax:

<div :class="{ active: isActive }"></div>

active is the name of the class and isActive is the condition when active is toggled on.

active is only on with isActive is truthy.

We can have multiple classes in one object.

For instance, we can write:

<div
  class="static"
  :class="{ active: isActive, 'has-error': hasError }"
></div>

We have the static static class which is always added.

And we have the class within the :class binding that’s only on when the conditions are truthy.

Bound objects don’t have to be inline, so we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div class="static" :class="classObj"></div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            classObj: {
              active: true,
              "has-error": false
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to pass in classObj as the value of the :class binding.

Array Syntax

We can also have class names in an array.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div :class="[activeClass, errorClass]"></div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            activeClass: "active",
            errorClass: "has-error"
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the activeClass and errorClass in an array.

We can toggle them on and off with JavaScript code.

If we want to toggle a class conditionally, we can write ternary expressions for them.

For example, we can write:

<div :class="[isActive ? activeClass : '', errorClass]"></div>

activeClass is only added is isActive is truthy.

Otherwise, the expression returns an empty string.

Classes With Components

We can add classes with components.

For instance, if we have:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <hello-world class="baz qux"></hello-world>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("hello-world", {
        template: `<p class="foo bar">hello world</p>`
      });

      app.mount("#app");
    </script>
  </body>
</html>

We created the hello-world component with the foo and bar classes on the p element.

In addition, we have the baz and qux class on the hello-world component itself.

The classes from both places will be combined since the p element is the root element of the component.

So the baz and qux class will be added to the p element.

Class bindings also work.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <hello-world :class="{ active: isActive }"></hello-world>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            isActive: true
          };
        }
      });

      app.component("hello-world", {
        template: `<p class="foo bar">hello world</p>`
      });

      app.mount("#app");
    </script>
  </body>
</html>

We have the active class combined with the foo and bar classes on the p element since isActive is true .

Conclusion

We can add HTML classes dynamically with an object or an array.

They can be added to Vue components and HTML elements.

If they’re added to a component, then they’ll be added to the root element of the component.

Categories
Vue 3

Vue 3 — Vue Instance Properties and Templates

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at Vue instance hooks and create simple templates with Vue 3.

Vue Instance Properties

The Vue instance has some properties that are built into th app.

The $data property has the data that our Vue instance has.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      {{a}}
    </div>
    <script>
      const data = { a: 1 };

      const vm = Vue.createApp({
        data() {
          return data;
        }
      }).mount("#app");

      console.log(vm.$data.a);
    </script>
  </body>
</html>

We have the vm.$data.a property which is the same as what we return in the data method.

a would be 1.

Instance Lifecycle Hooks

A Vue instance has various lifecycle hooks that it goes through from the initial load to being destroyed.

The following is the lifecycle diagram:

Courtesy of https://v3.vuejs.org/guide/instance.html#lifecycle-diagram

When the Vue instance is created, it starts with the init events and lifecycle stage, which calls the beforeCreate method in the Vue instance.

Event listeners are attached and the lifecycle begins at this stage.

Then it initializes the injections and reactivity stage and calls the created method.

This stage is where Vue starts listening for changes for data changes in the Vue instance.

Then one of 2 things can happen depending on if there’s a template in our Vue instance.

If there is, then template is compiled.

Otherwise, it compiles the content of the element we mounted pour Vue instance to HTML.

Once either of those is done, then beforeMount method is run.

Then the $el property is added to the Vue instance. Then element’s content is replaced with the compiled content.

The mounted method is then run.

When the state changes, then beforeUpdate is run.

Once the Virtual DOM is updated, the updated method is run.

Once app.unmount is called, which means the component will be unmounted.

Then beforeUnmount is run.

And when it’s unmounted, the unmounted method is run.

The methods are optional in our component.

We only need to add them if we want to run something in those lifecycle stages.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      {{a}}
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            a: 1
          };
        },
        created() {
          console.log(this.a);
        }
      }).mount("#app");
    </script>
  </body>
</html>

to add our own code to the created hook, which runs when the component first listen to state changes.

Therefore, this.a ‘s value will be logged.

Template Syntax

Vue uses a HTML-base template syntax that lets us bind the value between the template and the Vue instance’s data.

Vue compiles the templates into Virtual DOM render functions.

This lets Vue figure out the least amount of changes to change the real DOM to render the latest data.

Interpolations

The most basic kind of data binding is text interpolation.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      {{a}}
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            a: 1
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

Then we see that a is 1, which is displayed on the screen.

This interpolate is updated every time a changes.

We can make the interpolation only update once with the v-once directive.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div v-once>{{a}}</div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            a: 1
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

{{a}} will still be displayed as 1 even if the value changes.

Conclusion

The Vue instance has its own lifecycle hook.

We can add the code needed to run code during various stages of a Vue instance lifecycle.

Vue has an easy to use template syntax for rendering data.

Categories
Vue 3

Vue 3 — v-model Modifiers and Components

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to use the Vue 3 v-model directive and create simple Vue 3 components.

Select Options

Select option values can be objects.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <select v-model="selected">
        <option :value="{ fruiit: 'apple' }">apple</option>
        <option :value="{ fruiit: 'orange' }">orange</option>
        <option :value="{ fruiit: 'grape' }">grape</option>
      </select>
      <p>{{ selected }}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return { selected: {} };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to create a select dropdown that has option values bound to objects.

:value accepts an object.

So when we select a value, we’ll see that selected would also be an object.

This is because we set v-model ‘s value to selected .

v-model Modifiers

v-model can take various modifiers.

.lazy

The .lazy modifier makes v-model sync with the Vue instance state after each change event.

By default, v-model syncs with the state after each input event is emitted.

We can use that by writing:

<input v-model.lazy="msg" />

.number

The .number modifier lets us convert whatever is entered to a number automatically.

For instance, we can write:

<input v-model.number="numApples" type="number" />

to convert numApples to a number automatically.

By default, an HTML input’s value is always a string, so this is a useful shorthand.

If the value can’t be parsed with parseFloat , then the original value is returned.

.trim

The .trim modifier automatically trims whitespace from user inputs.

We can use it by writing:

<input v-model.trim="msg" />

v-model with Components

v-model can be used with components as long as it emits an input event and takes in a value prop to populate the form control’s value.

This lets us make custom form control components easily.

Components Basics

We can create Vue components with the app.component method.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <button-counter />
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("button-counter", {
        data() {
          return {
            count: 0
          };
        },
        template: `
          <div>
            <button @click="count++">
              increment
            </button>
            <p>{{ count }}</p>
          </div>
        `
      });

      app.mount("#app");
    </script>
  </body>
</html>

to create a component and then use it in our app.

We called app.component to with the component name as the first argument.

We called our component 'button-counter' .

The 2nd argument has the component object with the template and logic.

data returns the initial state object.

And template has the template string with the elements we want to display.

Inside it, we increment the count when a button is clicked and display the count .

Then we use the button-counter component in our app by adding the HTML for it.

Now we should see the increment button and the count value update as we click it.

Conclusion

v-model works with select options and components.

We can create simple components with the app.component method.