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.

Categories
Vue 3

Vue 3 — Component Basics

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 simple Vue 3 components.

Components

Components are reusable Vue instances with a name.

For instance, we can create a component 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-counter ></button-counter>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("button-counter", {
        data() {
          return {
            count: 0
          };
        },
        template: `
          <div>
            <button @click="count--">
              decrement
            </button>
            <p>{{ count }}</p>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We create a component with a button and a p element.

When we click the button, the count is decrement, and the value is displayed in the p element.

Then we used the button-counter element in the app’s template.

We can reuse the component multiple times.

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-counter></button-counter>
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
    <script>
      const app = Vue.createApp({}); 
      app.component("button-counter", {
        data() {
          return {
            count: 0
          };
        },
        template: `
          <div>
            <button @click="count--">
              decrement
            </button>
            <p>{{ count }}</p>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

Now we have 3 instances of the button-counter component.

They all have their own template and state.

Organizing Components

We got to organize our components well since we’ll probably have many of them in an app.

We can put them in a tree.

So we divide our app into small components we nest components to build what we want.

Passing Data to Child Components with Props

Our previous example didn’t have any way to get data from a parent component.

However, Vue 3 provides us with a way to pass data from parent to child with props.

Props are custom attributes that we can register on a component.

When a value is passed into the prop attribute, it becomes a property of the component instance.

For instance, we can create a component that takes props and 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">
      <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 create the blog-post component with the title prop so that we can display it on the template.

The props property has an array of strings of the prop names.

Having that means we registered that props to be allowed to be passed into our component.

A component can have as many props as we want.

If we have an array of data, we can use the v-for directive to render them.

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">
      <todo-item v-for="t of todos" :todo="t" :key="t.id"></todo-item>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        }
      }); 

      app.component("todo-item", {
        props: ["todo"],
        template: `<p>{{ todo.name }}</p>`
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

to render an array with components.

We have the todo-item component with the todo prop registered.

The template property rendered the name property of the array.

todo-item is used with v-for to render the todo items.

We pass in the todo value with the todo prop with :todo='t' and do the same with the key prop.

The key prop is used to let Vue identify each element uniquely.

Conclusion

We can create our own components with the app.component method so that we can divide our Vue app into manageable pieces.

Categories
NativeScript Vue

NativeScript Vue — Full Screen Modal and Tabs

Vue is an easy to use framework for building front end apps.

NativeScript is a mobile app framework that lets us build native mobile apps with popular front end frameworks.

In this article, we’ll look at how to build an app with NativeScript Vue.

Full Screen Modal

We can show a full-screen modal by writing:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Modal" @tap="openModal" />
    </FlexboxLayout>
  </Page>
</template>

<script>
const Detail = {
  props: ["id"],
  template: `
    <Page>
      <ActionBar title="Detail"/>
      <StackLayout>
        <Label :text="id" />
        <Button @tap="$modal.close" text="Close" />
      </StackLayout>
    </Page>
  `,
};
export default {
  methods: {
    openModal() {
      this.$showModal(Detail, { fullscreen: true, props: { id: 1 } });
    },
  },
};
</script>

We call the $showModal method with the Detail component.

And we set the fullscreen property to true to make the modal full screen.

Return Data from the Modal

We can return data from the modal.

For example, we can write:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Modal" @tap="openModal" />
    </FlexboxLayout>
  </Page>
</template>

<script>
const Detail = {
  props: ["id"],
  template: `
    <Page>
      <ActionBar title="Detail"/>
      <StackLayout>
        <Label text="Detail" />
        <Button @tap="$modal.close('foo')" text="Close" />
      </StackLayout>
    </Page>
  `,
};
export default {
  methods: {
    async openModal() {
      const data = await this.$showModal(Detail);
      console.log(data);
    },
  },
};
</script>

In the Detail component, we pass in the 'foo' argument in the $modal.close method.

Then we can get that value as the resolved value of the promise returned by $showModal .

BottomNavigation

We can add a navigation bar to the bottom of our screen by writing:

src/mainl.js

import Vue from 'nativescript-vue'
import App from './components/App'
import VueDevtools from 'nativescript-vue-devtools'

if (TNS_ENV !== 'production') {
  Vue.use(VueDevtools)
}

// Prints Vue logs when --env.production is *NOT* set while building
Vue.config.silent = (TNS_ENV === 'production')

new Vue({
  render: h => h(App)
}).$start()

src/components/App.vue

<template>
  <Page>
    <FlexboxLayout flexDirection="column">
      <BottomNavigation>
        <TabStrip>
          <TabStripItem>
            <Label text="Home"></Label>
          </TabStripItem>
          <TabStripItem>
            <Label text="Browse"></Label>
          </TabStripItem>
          <TabStripItem>
            <Label text="Search"></Label>
          </TabStripItem>
        </TabStrip>
        <TabContentItem>
          <Frame id="homeTabFrame">
            <Page>
              <Label text="home" />
            </Page>
          </Frame>
        </TabContentItem>
        <TabContentItem>
          <Frame id="browseTabFrame">
            <Page>
              <Label text="browse" />
            </Page>
          </Frame>
        </TabContentItem>
        <TabContentItem>
          <Frame id="searchTabFrame">
            <Page>
              <Label text="search" />
            </Page>
          </Frame>
        </TabContentItem>
      </BottomNavigation>
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {};
</script>

We render the App component in main.js .

Then in the App component, we add the BottomNavigation component to add the bottom navigation bar.

The TabStrip has the navigation links.

TabStripItem has the content for the tabs.

TabContentItem has the content for the tabs.

The TabContentItem s have the Frame s to show in the tab.

Conclusion

We can add full-screen modals and tabs into our mobile app with NativeScript Vue.

Categories
NativeScript Vue

NativeScript Vue — Navigation and Modals

Vue is an easy to use framework for building front end apps.

NativeScript is a mobile app framework that lets us build native mobile apps with popular front end frameworks.

In this article, we’ll look at how to build an app with NativeScript Vue.

Navigation

We can use the $navigateTo method lets us show different components in our app.

For example, we can write:

components/App.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go to Detail" @tap="goTo" />
    </FlexboxLayout>
  </Page>
</template>

<script>
import Detail from "@/components/Detail";

export default {
  methods: {
    goTo() {
      this.$navigateTo(Detail);
    },
  },
};
</script>

components/Detail.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go to App" @tap="goTo" />
    </FlexboxLayout>
  </Page>
</template>

<script>
import App from "@/components/App";

export default {
  methods: {
    goTo() {
      this.$navigateTo(App);
    },
  },
};
</script>

In the App component, we call this.$navigateTo with the Detail component to remove App from the screen show the Detail component.

Likewise, in the Detail component, we call the same method with the App component to replace the Detail component with the App component.

We can pass props to the component.

For instance, we can write:

components/App.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go to Detail" @tap="goTo" />
    </FlexboxLayout>
  </Page>
</template>

<script>
import Detail from "@/components/Detail";

export default {
  methods: {
    goTo() {
      this.$navigateTo(Detail, {
        props: {
          foo: "bar",
        },
      });
    },
  },
};
</script>

components/Detail.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go to App" @tap="goTo" />
      <Label :text="foo" style="text-align: center" />
    </FlexboxLayout>
  </Page>
</template>

<script>
import App from "@/components/App";

export default {
  props: ["foo"],
  methods: {
    goTo() {
      this.$navigateTo(App);
    },
  },
};
</script>

In the App component, we pass in an object into the 2nd argument with the props property to pass in props.

Then in the Detail component, we accept the prop as the props property.

And then we get its value and display it in the Label .

We can go back to the previous page with the $navigateBack method.

To use it, we can write:

components/App.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go to Detail" @tap="goTo" />
    </FlexboxLayout>
  </Page>
</template>

<script>
import Detail from "@/components/Detail";

export default {
  methods: {
    goTo() {
      this.$navigateTo(Detail);
    },
  },
};
</script>

components/Detail.vue

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Go Back" @tap="goTo" />
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {
  methods: {
    goTo() {
      this.$navigateBack();
    },
  },
};
</script>

We have the Detail component that calls the this.$navigateBack method when we tap on the button.

Modals

We can use the this.$showModal method to show a modal.

For example, we can write:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Modal" @tap="openModal" />
    </FlexboxLayout>
  </Page>
</template>

<script>
const Detail = {
  props: ["id"],
  template: `
    <Page>
      <ActionBar title="Detail"/>
      <StackLayout>
        <Label :text="id" />
        <Button @tap="$modal.close" text="Close" />
      </StackLayout>
    </Page>
  `,
};

export default {
  methods: {
    openModal() {
      this.$showModal(Detail, { props: { id: 1 } });
    },
  },
};
</script>

We call the $showModal method with the Detail component.

And we can pass in props by setting the props property.

Conclusion

We can add navigation and show modals into our mobile app with NativeScript Vue.

Categories
NativeScript Vue

NativeScript Vue — Login and Prompt Dialogs

Vue is an easy to use framework for building front end apps.

NativeScript is a mobile app framework that lets us build native mobile apps with popular front end frameworks.

In this article, we’ll look at how to build an app with NativeScript Vue.

LoginDialog

NativeScript Vue comes with a login dialog.

For example, we can write:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Dialog" @tap="openDialog" />
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {
  methods: {
    async openDialog() {
      const result = await login("Login", "Username field", "Password field");
      const { result: res, userName, password } = result;
      console.log(res, userName, password);
    },
  },
};
</script>

We have a button to open the login dialog.

The login function opens the login dialog.

The first argument is the message content.

The 2nd and 3rd arguments are the placeholders for the username and password inputs respectively.

Then we can get the values of the username and password from the resolved value.

res has the form validation result.

We can set more options by writing:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Dialog" @tap="openDialog" />
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {
  methods: {
    async openDialog() {
      const result = await login({
        title: "Login Title",
        message: "Login message",
        okButtonText: "OK",
        cancelButtonText: "Cancel",
        userName: "user",
        password: "password",
      });
      const { result: res, userName, password } = result;
      console.log(res, userName, password);
    },
  },
};
</script>

title has the login dialog title.

message has the message for the login dialog.

okButtonText sets the OK button’s text.

cancelButtonText sets the cancel button’s text.

userName sets the default value of the username field.

And password sets the default value of the password field.

PromptDialog

The prompt global function lets us open a dialog with a single-line text input.

To use it, we can write:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Dialog" @tap="openDialog" />
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {
  methods: {
    async openDialog() {
      const result = await prompt(
        "Enter something",
        "Suggested user input"
      );
      console.log(result);
    },
  },
};
</script>

We have a button to open the prompt dialog.

The prompt method takes the dialog text as the first argument and the default value for the input as the 2nd argument.

We can also add more options. For example, we can write:

<template>
  <Page>
    <ActionBar title="NativeScript App"></ActionBar>
    <FlexboxLayout flexDirection="column">
      <Button text="Open Dialog" @tap="openDialog" />
    </FlexboxLayout>
  </Page>
</template>

<script>
export default {
  methods: {
    async openDialog() {
      const result = await prompt({
        title: "Title",
        message: "Enter something",
        okButtonText: "OK",
        cancelButtonText: "Cancel",
        defaultText: "Suggested value",
      });
      console.log(result);
    },
  },
};
</script>

We set the title value to show the dialog title.

message has the dialog message.

okButtonText has the OK button text.

cancelButtonText has the cancel button text.

defaultText has the default value for the input.

Conclusion

We can add a login and prompt dialog into our mobile app with NativeScript Vue.