Categories
Vue 3

Vue 3 — Conditional Rendering

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 conditionally rendering items with Vue.

v-else

We can use v-else to display an alternative item with the value in v-if is falsy.

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 @click="on = !on">toggle</button>  
      <h1 v-if="on">hello</h1>  
      <h1 v-else>bye</h1>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        data() {  
          return {  
            on: true  
          };  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

When we toggle on to true , the ‘hello’ is displayed.

Otherwise, ‘bye’ is displayed.

v-else must immediately follow a v-if or a v-else-if element.

Otherwise, it won’t be recognized.

Conditional Groups with v-if on <template>

v-if can be used on template so that we can conditionally display a group of elements.

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 @click="on = !on">toggle</button>  
      <template v-if="on">  
        <h1>Title</h1>  
        <p>Paragraph 1</p>  
        <p>Paragraph 2</p>  
      </template>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        data() {  
          return {  
            on: true  
          };  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We have the v-if added to the template so that we can toggle everything inside all at once.

v-else-if

We can use v-else-if to display something if a case is true .

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">  
      <div v-if="type === 'a'">  
        a  
      </div>  
      <div v-else-if="type === 'b'">  
        b  
      </div>  
      <div v-else-if="type === 'c'">  
        c  
      </div>  
      <div v-else>  
        something else  
      </div>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        data() {  
          return {  
            type: "a"  
          };  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We have the v-else-if directive to display the different items according to the value of type .

Since we set it to 'a' , we’ll see ‘a’ displayed.

v-else-if must be immediately after v-if or another v-else-if element.

v-show

The v-show directive also lets us conditionally rendering items on the screen.

But the difference is that v-show elements always render on the DOM and it’s hidden with CSS if its value is falsy.

v-show doesn’t support the template element and can’t be used with v-else .

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">  
      <button @click="on = !on">toggle</button>  
      <h1 v-show="on">hello</h1>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        data() {  
          return {  
            on: true  
          };  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We have the v-show directive which will toggle the CSS display property to show or hide the h1 element.

v-if vs v-show

v-if is real conditional rendering because all the event listeners and child components are destroyed when they aren’t rendered.

v-if is lazy, so if its value is falsy, it won’t be rendered until it becomes true .

v-show is much simpler, it just toggles the display CSS property to change the display.

v-show is better if we need to toggle something often and v-if is good for other cases.

Conclusion

We can use v-if and v-show to conditionally render items.

v-if changes the DOM structure, and v-show changes the CSS only.

Categories
Vue 3

Vue 3 — HTML and Directives

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 create templates with Vue 3.

Raw HTML

We can render raw HTML with the v-html directive.

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">
      <p>{{ rawHtml }}</p>
      <p><span v-html="rawHtml"></span></p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            rawHtml: `<b>foo</b>`
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the rawHtml property returned with the object we return in the data method.

If we pass raw HTML into the mustache, it’ll be sanitized. This means the raw code will be displayed.

If we pass it into the v-html directive, it’ll be displayed as HTML, so it’ll be bold.

Therefore, if we use v-html , we should be careful of cross-site scripting vulnerabilities.

We should only display trusted content with v-html .

Attributes

If we want to set attribute values dynamically, we’ve to use the v-bind 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-bind:id="dynamicId"></div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            dynamicId: `foo`
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to set the id attribute of the div to foo by using v-bind .

If we have boolean attributes, its existence means we set the value totrue .

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 v-bind:disabled="disabled">Button</button>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            disabled: true
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We disabled the button by passing in the disabled value to v-bind:disabled , which is true .

JavaScript Expressions

We can put JavaScript expressions between the double curly braces.

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">
      {{message.split('').reverse().join('')}}
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            message: "hello world"
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to reverse 'hello world' in the template.

We can only put in single expressions and not statements, so we can’t write:

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

The Vue template compiler will give us an error.

Directives

Directives are special attributes that starts with v- .

The values they expect are single JavaScript expressions.

v-for and v-on are exceptions to this.

We reactively apply the side effects to the DOM when the value of its expression changes.

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">
      <p v-if="show">hello world</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            show: true
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to show the ‘hello world’ message with v-if since show is true .

v-if is a directive that shows something when its value is truthy.

Conclusion

Templates can have raw HTML, attributes, and directives.

Directives are special attributes that take values.

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.