Categories
Vue 3

Vue 3 — v-for and Components

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 rendering arrays with v-for .

Methods

We can use methods to render with v-for as long as the method returns an array or an object.

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">
      <ul v-for="numbers in sets">
        <li v-for="n in odd(numbers)">{{ n }}</li>
      </ul>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            sets: [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
          };
        },
        methods: {
          odd(numbers) {
            return numbers.filter(number => number % 2 === 1);
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

to get the odd numbers from each nested array and render them.

The odd method takes a number array and returns an array with the odd ones, so we can use it with v-for .

v-for with a Range

v-for can be used to render a range of numbers.

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 id="range">
        <p v-for="n in 100">{{ n }}</p>
      </div>
    </div>
    <script>
      const vm = Vue.createApp({}).mount("#app");
    </script>
  </body>
</html>

n in 100 will render a list of numbers from 1 to 100.

v-for on a <template>

v-for can be used on the template element to let us render a group of items.

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">
      <template v-for="p in people">
        <p>{{ p.name }}</p>
        <hr />
      </template>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            people: [
              { id: 1, name: "mary" },
              { id: 2, name: "james" },
              { id: 3, name: "jane" }
            ]
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the p and hr elements rendered in a group in the template tag.

This way, we can render multiple items in a group.

v-for with a Component

v-for can be used with components.

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">
      <person v-for="p in people" :person="p" :key="p.id"> </person>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            people: [
              { id: 1, name: "mary" },
              { id: 2, name: "james" },
              { id: 3, name: "jane" }
            ]
          };
        }
      });

      app.component("person", {
        props: ["person"],
        template: `
          <p>{{ person.name }}</p>
          <hr />
        `
      });

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

to create a component called person .

It takes the person prop, which are objects in the people array.

Then we pass in each people entry as the value of the person prop.

The items in the component are rendered as the v-for loop runs.

The data isn’t automatically injected into the component since it makes the coupling tight between the child and the parent component.

Conclusion

We can render arrays and objects returned from methods.

Categories
Vue 3

Vue 3 — v-for and Arrays

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 rendering arrays with v-for .

Maintaining State

When v-for re-renders a list, the items are patched in place.

When then items change, the existing items are updated.

However, this means when the items re-render, their state will be cleared.

Therefore, patching is only suitable when we render a list that doesn’t rely on child component state or temporary DOM state.

To let Vue know the identity of an item, we should add a key prop to each rendered item so that Vue can reuse and reorder existing 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">
      <div v-for="p in people" :key="p.id">
        {{ p.name }}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            people: [
              { id: 1, name: "mary" },
              { id: 2, name: "james" },
              { id: 3, name: "jane" }
            ]
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to render a list from the people array.

We passed in a unique ID to the key prop to make sure that the ID stays the same no matter what order the items are in.

Only primitive values should be used as key values.

So we can use strings or numbers like in the example.

Array Change Detection

Vue 3 wraps array mutation methods so they also trigger view updates.

The wrapped methods include:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

They’ll all trigger Vue to update the rendered list when they’re called.

Replacing an Array

Methods that return a new array don’t trigger Vue to update the rendered list because they return a new array.

Therefore, we need to assign the returned array to the original value.

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">
      <input v-model="name" @keydown="search" />
      <div v-for="p in people" :key="p.id">
        {{ p.name }}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            name: "",
            people: [
              { id: 1, name: "mary" },
              { id: 2, name: "james" },
              { id: 3, name: "jane" }
            ]
          };
        },
        mounted() {
          this.orig = JSON.parse(JSON.stringify(this.people));
        },
        methods: {
          search() {
            if (this.name.length > 0) {
              this.people = this.people.filter(item =>
                item.name.match(new RegExp(this.name, "g"))
              );
            } else {
              this.people = this.orig;
            }
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

We called the filter method to filter items according to the inputted value.

So we’ve set the returned value to the this.people property so that the new value will be rendered.

Displaying Filtered/Sorted Results

If we want to display filtered or sorted results, we can do this with 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">
      <p v-for="n in oddNumbers">{{ n }}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            numbers: [1, 2, 3, 4, 5]
          };
        },
        computed: {
          oddNumbers() {
            return this.numbers.filter(number => number % 2 === 1);
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>

to return an array of odd numbers in the computed property oddNumbers .

Then we can render oddNumbers instead of the original number array and using v-if to do the filtering.

Conclusion

We can use computed properties to display filtered values.

Array methods that mutate the array will trigger re-render when they’re called.

Array methods that return the new array will need to have their returned value assigned to an instance variable for them to be rendered.

Categories
Vue 3

Vue 3 — v-for

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 rendering arrays and objects with v-for .

v-if with v-for

We shouldn’t use v-if and v-for together.

This is because v-for renders everything and then v-if checks every item whether they need to be rendered.

Instead, we should filter out the items beforehand with computed properties and use that with v-for .

When they’re used together, v-for has higher priority over v-if .

List Rendering

We can render an array of items onto the screen with v-for .

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-for="p in people">
        {{ p.name }}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            people: [{ name: "mary" }, { name: "james" }, { name: "jane" }]
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to render the items in the people array onto the screen.

We use the v-for directive to loop through each entry and render each item onto the screen.

We can also get the index of the item by writing:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg._com_/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div v-for="(p, index) in people">
        {{index}} - {{ p.name }}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            people: [{ name: "mary" }, { name: "james" }, { name: "jane" }]
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

Then we get the index of the item with index.

We used in to loop through the array, but we can replace in with of to make it resemble the for-of loop:

<div v-for="p of people"></div>

v-for with an Object

v-for also works for 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">
      <div v-for="value in obj">
        {{value}}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            obj: {
              james: 20,
              mary: 30,
              jane: 10
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to loop through the values of an object and display each value.

To get the key, we can add a second parameter to the loop:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div v-for="(value, name) in obj">
        {{name}}: {{value}}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            obj: {
              james: 20,
              mary: 30,
              jane: 10
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

name has the key of the object.

The 3rd item in the comma-separated list is the index:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div v-for="(value, name, index) in obj">
        {{index}} - {{name}}: {{value}}
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            obj: {
              james: 20,
              mary: 30,
              jane: 10
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

Conclusion

We can render objects and arrays with the v-for directive.

Categories
Vue 3

Vue 3 — Inline Styles and v-if

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 inline style bindings and v-if.

Binding Inline Styles

There’re various ways to bind inline styles to an element.

One way is to pass in an object to the :style 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">
      <div :style="{ color, fontSize: `${fontSize}px` }">
        hello
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            color: "red",
            fontSize: 30
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the color and fontSize properties in the object we return in the data method.

Then we used that in the object we use as the value of the :style directive.

So ‘hello’ should be red and 30px in size.

We can replace that with an object to make the template shorter.

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 :style="styleObj">
        hello
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            styleObj: {
              color: "red",
              fontSize: "30px"
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

There’s also an array syntax to let us add multiple style objects to the same element.

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 :style="[baseStyles, overridingStyles]">
        hello
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            baseStyle: {
              color: "red",
              fontSize: "30px"
            },
            overridingStyles: {
              color: "green"
            }
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have the baseStyles and overridingStyles in one array.

The styles in overridingStyles will override the styles in baseStyle completely.

So we get that the text is green and it’s in its default size.

If browser-specific prefixes are needed, then they’ll be added automatically.

We can also provide an array of values to a style property with 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 :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">
        hello
      </div>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {};
        }
      }).mount("#app");
    </script>
  </body>
</html>

We have all the variants of flex in the array.

Conditional Rendering

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

We have the on property returned with the object we return indata , so we can use it with v-if to conditionally render the h1 element.

Also, we have a button to toggle on between true or false so that we’ll see the h1 toggled on and off as we click the button.

Conclusion

Inline styles can be added with the :style directive.

It takes an object or an array.

We can use v-if to conditionally render an element.

Categories
Vue 3

Vue 3 — Event Handling

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 handle events in Vue 3 components.

Listening to Events

We can listen to events with the v-on directive, or @ for short.

For instance, we can listen to clicks 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 v-on:click="onClick">click me</button>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        methods: {  
          onClick() {  
            alert("clicked");  
          }  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We added the v-on:click directive to run the onClick method when we click the button.

So we should see an alert when we click the button.

To shorten it, 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="onClick">click me</button>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        methods: {  
          onClick() {  
            alert("clicked");  
          }  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We can put any JavaScript expression as the value of the v-on directive.

Methods in Inline Handlers

We don’t have to bind directly to the method in the expression we pass into v-on .

We can also call the method in there.

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="onClick('hi')">hi</button>  
      <button @click="onClick('bye')">bye</button>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        methods: {  
          onClick(str) {  
            alert(str);  
          }  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

We pass in an argument to the onClick method so that onClick will get the argument and display the message.

To access the event object of the event, we can use the $event object.

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="onClick('hi', $event)">click me</button>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        methods: {  
          onClick(str, event) {  
            event.stopPropagation();  
            alert(str);  
          }  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

to pass in the $event object to our event handler.

Then we can call stopPropagation on it to stop the click event from propagation to parent elements.

This event object is the native event object.

Multiple Event Handlers

We can have multiple event handlers in one expression.

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="one($event), two($event)">click me</button>  
    </div>  
    <script>  
      const vm = Vue.createApp({  
        methods: {  
          one(event) {  
            console.log("one");  
          },  
          two(event) {  
            console.log("two");  
          }  
        }  
      }).mount("#app");  
    </script>  
  </body>  
</html>

to run one and two as event handlers when we click on the button.

Event Modifiers

We can add event modifiers so that we don’t have to call methods like event.preventDefault() or event.stopPropagation() in our event handlers.

The modifiers include:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive

These are added to the v-on directive.

For example, to call event.stopPropagation in our event handler, we can write:

<a @click.stop="onClick"></a>

then the click event won’t be propagated to the parent elements.

And if we write:

<form @submit.prevent="onSubmit"></form>

event.preventDefault() will be called when running onSubmit .

Modifiers can also be chained, so we can write:

<a @click.stop.prevent="onClick"></a>

The capture modifier lets us use capture mode when adding an event listener.

And the self modifier only triggers the event handler if the event.target is the element itself.

once will only trigger the event handler at most once.

The passive modifier corresponds to the addEventListener ‘s passive option.

If we add it to the @scroll directive:

<div @scroll.passive="onScroll">...</div>

then the scroll event’s default behavior will happen immediately instead of waiting for onScroll to complete.

passive and prevent shouldn’t be used together since prevent will be ignored.

passive communicates to the browser that we don’t want to prevent the default browser behavior.

Conclusion

We can listen to events with the v-on directives.

It makes many arguments and modifiers.