Categories
Vuetify

Vuetify — Alert, Containers, and Avatars

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Alert Transition

Transition effects can be applied when we add alerts.

For instance, we can write:

<template>
  <v-container>
    <v-row class="text-center">
      <v-col col="12">
        <div class="text-center mb-4">
          <v-btn color="primary" @click="alert = !alert">Toggle</v-btn>
        </div>
        <v-alert
          :value="alert"
          color="pink"
          dark
          border="top"
          icon="mdi-home"
          transition="scale-transition"
        >
          lorem ipsum
        </v-alert>
      </v-col>
    </v-row>
  </v-container>
</template><script>
export default {
  name: "HelloWorld",
  data: () => ({
    alert: false
  }),
};
</script>

to add our alert with the transition.

We just add the transition prop to add the effect.

Application

The v-app component is a container for components like v-navigator-drawer , v-app-bar , v-footer , and other components.

It helps create our app with proper sizing around the v-main component.

This lets us avoid the hassle of managing layout sizing.

v-app is required for all apps.

It ensures that the proper styles are applied to the whole app.

Also, it should only be included once.

For example, we can write:

<template>
  <v-app>
    <v-app-bar
      app
      color="primary"
      dark
    >
      <div class="d-flex align-center">
        <v-img
          alt="Vuetify Logo"
          class="shrink mr-2"
          contain
          src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
          transition="scale-transition"
          width="40"
        /><v-img
          alt="Vuetify Name"
          class="shrink mt-1 hidden-sm-and-down"
          contain
          min-width="100"
          src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
          width="100"
        />
      </div> <v-spacer></v-spacer> <v-btn
        href="https://github.com/vuetifyjs/vuetify/releases/latest"
        target="_blank"
        text
      >
        <span class="mr-2">Latest Release</span>
        <v-icon>mdi-open-in-new</v-icon>
      </v-btn>
    </v-app-bar> <v-main>
      <HelloWorld/>
    </v-main>
  </v-app>
</template><script>
import HelloWorld from './components/HelloWorld';export default {
  name: 'App', components: {
    HelloWorld,
  }, data: () => ({
    //
  }),
};
</script>

to use it.

v-app wraps around the whole app.

And we can have all the other Vuetify components inside.

Aspect Ratios

We can use the v-responsive component to add a container with a specific aspect ratio.

For example, we can write:

<template>
  <v-container>
    <v-row class="text-center">
      <v-col col="12">
        <v-responsive :aspect-ratio="16/9">
          <v-card-text>Lorem ipsum</v-card-text>
        </v-responsive>
      </v-col>
    </v-row>
  </v-container>
</template><script>
export default {
  name: "HelloWorld",
  data: () => ({
    alert: false,
  }),
};
</script>

We added a 16×9 container with the v-response component and the aspect-ratio prop.

Avatars

The v-avatar component lets us display circular user profile pictures.

For example, we can add one by writing:

<template>
  <v-container>
    <v-row class="text-center">
      <v-col col="12">
        <v-avatar color="green" size="36">
          <span class="white--text headline">36</span>
        </v-avatar>
      </v-col>
    </v-row>
  </v-container>
</template><script>
export default {
  name: "HelloWorld",
  data: () => ({
    alert: false,
  }),
};
</script>

We added a green avatar with the color prop.

size is in pixels.

Also, we can make it square with a tile prop:

<template>
  <v-container>
    <v-row class="text-center">
      <v-col col="12">
        <v-avatar tile color="blue">
          <v-icon dark>mdi-alarm</v-icon>
        </v-avatar>
      </v-col>
    </v-row>
  </v-container>
</template><script>
export default {
  name: "HelloWorld",
  data: () => ({
    alert: false,
  }),
};
</script>

The default slot of v-avatar accepts the v-icon component, image or text.

We can write:

<template>
  <v-container>
    <v-row class="text-center">
      <v-col col="12">
        <v-avatar color="blue">
          <v-avatar>
            <img src="https://cdn.vuetifyjs.com/images/john.jpg" alt="John" />
          </v-avatar>
        </v-avatar>
      </v-col>
    </v-row>
  </v-container>
</template><script>
export default {
  name: "HelloWorld",
  data: () => ({
    alert: false,
  }),
};
</script>

to add an image.

Conclusion

We can add alerts, avatars, and responsive containers with Vuetify.

Categories
Vue 3

Vue 3 — Props Data Flow

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

One-Way Data Flow

Props have a one way downward binding between the parent and child component.

When the parent property updates, then the updates are passed into the child via props.

This prevents child components from accidentally mutating the parent’s state.

And this makes our app easier to understand.

We should never mutate props.

If we need to change their value, then we should assign them to a new property first.

For instance, if we need to change the value of an initial value that’s set with the prop’s value, then we should assign that to a state first.

So we should write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <counter :initial-count="5"></counter>
    </div>
    <script>
      const app = Vue.createApp({}); app.component("counter", {
        props: ["initialCount"],
        data() {
          return {
            count: this.initialCount
          };
        },
        template: `
          <div>
            <button @click='count++'>increment</button>
            <p>{{count}}</p>
          </div>
        `
      }); app.mount("#app");
    </script>
  </body>
</html>

We have the initialCount prop that we use to set the initial value of count state in the counter component.

Then we can do whatever we like with it.

If the value needs to be transformed, then we can put it in as a computed 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">
      <counter :initial-count="5"></counter>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("counter", {
        props: ["initialCount"],
        data() {
          return {
            count: this.initialCount
          };
        },
        computed: {
          doubleCount() {
            return this.count * 2;
          }
        },
        template: `
          <div>
            <button @click='count++'>increment</button>
            <p>{{doubleCount}}</p>
          </div>
        `
      }); app.mount("#app");
    </script>
  </body>
</html>

We have the initial-count prop which is transformed to doubleCount by returning this.count * 2 .

Now we don’t have to do anything with the prop value itself.

And we just change the state to what we want within the data method and the computed property in the counter component.

Prop Validation

We can validate props by check its data type and more.

We set the the props property’s value to a constructor.

Or we can validate it with a function.

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">
      <blog-post v-for="post of posts"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ author: "james", likes: 100 }]
          };
        }
      });
      app.component("blog-post", {
        props: {
          title: {
            type: String,
            default: "default title"
          }
        },
        template: `<p>{{title}}</p>`
      });
      app.mount("#app");
    </script>
  </body>
</html>

Then we get the ‘default title’ text displayed since we never passed in value to the title prop.

default has the default value.

validator has the validator function for props.

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">
      <blog-post v-for="post of posts" type="news"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ author: "james", likes: 100 }]
          };
        }
      });
      app.component("blog-post", {
        props: {
          type: {
            validator(value) {
              return ["news", "announcement"].indexOf(value) !== -1;
            }
          }
        },
        template: `<p>{{type}}</p>`
      });
      app.mount("#app");
    </script>
  </body>
</html>

to add a validator for the type prop.

The validator method is run when we pass in the prop with the given name.

The value is the value that we pass in.

So if we pass in something other than 'new' or 'announcement' like:

<blog-post v-for="post of posts" type="foo"></blog-post>

then we’ll get a warning.

We can also add the required property and set it to true to make a prop required like:

prop: {
  type: String,
  required: true
}

Conclusion

We can validate props with constructors and validation functions.

Also, we can add the default property to set the default value of a prop.

Categories
Vue 3

Vue 3 — More Complex Props

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

Passing a Number

We can pass in numbers to props.

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">
      <blog-post v-for="post of posts" :likes="post.likes"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ title: "hello world", author: "james", likes: 100 }]
          };
        }
      }); 
      app.component("blog-post", {
        props: {
          likes: Number
        },
        template: `<p>{{likes}}</p>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

to create the blog-post component that takes the likes prop.

likes is a number, so we’ve to put the : before the likes to let us pass in an expression.

We can also pass in a number literal:

<blog-post :likes="100"></blog-post>

Passing a Boolean

To pass in a boolean, we can write:

<blog-post is-published></blog-post>

to pass in true to the is-published prop.

To pass in false , we’ve write out the whole expression:

<blog-post :is-published='false'></blog-post>

And we can pass in other expressions.

Passing an Array

We can pass in an array literal as a prop value.

So we can write:

<blog-post :comment-ids="[1, 2, 3]"></blog-post>

or we can write:

<blog-post :comment-ids="post.commentIds"></blog-post>

Passing an Object

Vue props can take objects.

So we can write:

<blog-post
  :author="{
    firstName: 'james',
    lastName: 'smith'
  }"
></blog-post>

We pass in an object to the author prop.

The : tells Vue that the object isn’t a string.

We can also pass in another expression that returns an object.

Passing the Properties of an Object

To pass in the properties of an object as props, we can use the v-bind without the argument.

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">
      <blog-post v-for="post of posts" v-bind="post"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ title: "hello world", author: "james", likes: 100 }]
          };
        }
      }); 
      app.component("blog-post", {
        props: {
          title: String,
          author: String,
          likes: Number
        },
        template: `
          <div>
            <h1>{{title}}</h1>
            <p>author: {{author}}</p>
            <p>likes: {{likes}}</p>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

Then the properties of post will be passed into blog-post as prop values.

The property names are the prop names.

This is a shorthand for:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <blog-post
        v-for="post of posts"
        :title="post.title"
        :author="post.author"
        :likes="post.likes"
      ></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [{ title: "hello world", author: "james", likes: 100 }]
          };
        }
      }); 
      app.component("blog-post", {
        props: {
          title: String,
          author: String,
          likes: Number
        },
        template: `
          <div>
            <h1>{{title}}</h1>
            <p>author: {{author}}</p>
            <p>likes: {{likes}}</p>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

As we can see, it’s much longer and a lot more repetitive than the shorthand.

Conclusion

We can pass in various kinds of data easily with Vue components.

We just need to use v-bind or : for short.

Categories
Vue

Vue 3 — Props

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

Props

Components can take props so that we can pass data from the parent component to it.

We can add props by defining the as an array of strings.

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">
      <blog-post title="hello world"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("blog-post", {
        props: ["title"],
        template: `<h1>{{title}}</h1>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We created a blog-post component with the props property to define which props we accept.

The array has the names of the props as strings.

Then we can pass in the props as we did with title .

Props are just attributes that can have any value we want.

Prop Types

To make passing props easier, we can check the data type of the prop.

This way, we’ll get an error if we pass in some value that we don’t expect.

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">
      <blog-post title="hello world"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("blog-post", {
        props: {
          title: String
        },
        template: `<h1>{{title}}</h1>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

to set the title prop type to a string.

We can pass in any other constructor to set the valid type of a prop, like:

props: {
  title: String,
  likes: Number,
  date: Date,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise
}

This also serves as good documentation of ur component.

Passing Static or Dynamic Props

Static props can be passed in with v-bind .

We did with the title prop in the previous example.

We have:

<blog-post title="hello world"></blog-post>

which has the title prop and it’s a static string.

If we want to pass in anything else, then we need to use v-bind or : for short.

For example, we can write:

<blog-post :title="post.title"></blog-post>

to pass in the title property of the post object.

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">
      <blog-post v-for="post of posts" :title="post.title"></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [
              { title: "hello world", author: "james" },
              { title: "good news", author: "james" },
              { title: "bad news", author: "james" }
            ]
          };
        }
      }); 

      app.component("blog-post", {
        props: {
          title: String
        },
        template: `<h1>{{title}}</h1>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

to pass the title property of post to the title prop.

We can also pass in an expression.

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">
      <blog-post
        v-for="post of posts"
        :title="`${post.title} by ${post.author}`"
      ></blog-post>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            posts: [
              { title: "hello world", author: "james" },
              { title: "good news", author: "mary" },
              { title: "bad news", author: "jane" }
            ]
          };
        }
      }); 

      app.component("blog-post", {
        props: {
          title: String
        },
        template: `<h1>{{title}}</h1>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We created a string from the title and author properties and pass that in as the title prop’s value.

Conclusion

We can register props to let us pass values to child components.

Also, we can validate the data type with constructors as the values of the prop property.

Categories
Vue 3

Vue 3 — Component Events

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 listen to component events.

Listening to Child Components Events

We can listen to child components within the parent component.

Our child component has to emit the event so that the parent component can listen to it.

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="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="fontSize++"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        }
      }); 
      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text')">
              Enlarge text
            </button>
        </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We created a todo-item component with an ‘enlarge text’ button.

When we click it, the $emit function is run.

The argument is the event name.

Then in the parent component that holds the todo-item component, we have the @enlarge-text directive so that we can listen to the enlarge-text event that’s emitted from todo-item .

When that event is received, when we increase fontSize by 1.

Since we set fontSize as the font size of our div, then font size change will be applied across all the child elements.

Emitting a Value With an Event

The $emit function takes a second argument with the value we want to emit with the event.

Therefore, we can modify our code to pass the value into the $emit function.

Then we get the value emitted from the $event 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">
      <div :style="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="fontSize += $event"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        }
      }); 

      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text', 1)">
              Enlarge text
            </button>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

$emit takes a second argument that we emit with the enlarge-text event.

Now in the parent component, we get the value emitted with the $event variable.

In this case, $event is set to 1 since that’s what we emitted.

We changed the @enlarge-text ‘s value so that the fontSize updates from the $event instead of a constant value.

Also, we can put the expression we passed into @enlarge-text into a method.

This is handy if we have more code.

For instance, 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">
      <div :style="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="onEnlargeText"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        },
        methods: {
          onEnlargeText(amount) {
            this.fontSize += amount;
          }
        }
      }); 

      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text', 1)">
              Enlarge text
            </button>
        </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We changed @enlarge-text ‘s value to our onEnlargeText method.

amount would be automatically set to the $event variable’s value, which is 1.

So we get the same result.

Conclusion

We can listen to the child component’s events from the parent.

This way, we can pass data from child to parent.