Categories
Vue 3

How to Remove the Hash from the URL with Vue Router 4?

Sometimes, we want to map our components to paths that don’t have a hash in front of it in our Vue 3 app that uses Vue Router 4.

In this article, we’ll look at how to remove the hash from the URL path with Vue Router 4.

Remove the Hash from the URL with Vue Router 4

We can remove the hash from the URLs with Vue Router 4 by calling the createWebHistory method.

For instance, we can write:

main.js

import { createApp } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import App from "./App.vue";
import Page1 from "./views/Page1";
import Page2 from "./views/Page2";
import Page3 from "./views/Page3";

const routes = [
  { path: "/", component: Page1 },
  { path: "/page2", component: Page2 },
  { path: "/page3", component: Page3 }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

const app = createApp(App);
app.use(router);
app.mount("#app");

App.vue

<template>
  <router-link to="/">page 1</router-link>
  <router-link to="/page2">page 2</router-link>
  <router-link to="/page3">page 3</router-link>
  <router-view></router-view>
</template>

<script>
export default {
  name: "App"
};
</script>

views/Page1.vue

<template>
  <div>page 1</div>
</template>

views/Page2.vue

<template>
  <div>page 2</div>
</template>

views/Page3.vue

<template>
  <div>page 3</div>
</template>

In main.js , we have the routes array with the route definitions.

We map the URL paths to components.

Then we call createRouter with an object that has the history property set to value returned by createWebHistory .

createWebHistory set the router to HTML5 history mode to remove the hash.

This will remove the hash from the paths that are mapped by Vue Router 4.

We also set the routes property to the routes array to add the routes we created.

Next, we call app.use with router to add the router object.

In App.vue , we have the router-link s to render the links.

router-view render the route page components.

Page1 , Page2 and Page3 are route components.

Now when we click on the router links, we shouldn’t see the hash in between the hostname and the route paths.

Conclusion

We can remove the hash from the URL with Vue Router 4’s createWebHistory function.

Categories
Vue 3

How to Disable Input Conditionally in Vue.js 3?

Sometimes, we may want to disable inputs conditionally in our Vue 3 apps.

In this article, we’ll look at how to disable input elements conditionally in Vue 3.

Disable Input Conditionally in Vue.js 3

We can disable inputs conditionally with Vue 3 by setting the disabled prop to the condition when we want to disable the input.

For instance, we can write:

<template>
  <input :disabled="disabled" />
  <button @click="disabled = !disabled">toggle disable</button>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      disabled: false,
    };
  },
};
</script>

We have the input with the disabled prop set to the disabled reactive property.

Below that, we have the @click directive to toggle the disabled reactive property when we click the button.

When disabled is true , then the input will be disabled.

So when we click the button repeatedly, the input will be disabled and enabled again.

Conclusion

We can conditionally disable an input with Vue 3 by setting the disabled prop of the input to an expression that has the condition of when we want to disable the input.

Categories
Vue 3

How to Properly Watch for Nested Data in Vue.js 3 Components?

Sometimes, we’ve to watch for nested data in Vue 3 components.

In this article, we’ll look at how to watch for nested data in Vue 3 components.

Adding Nested Data Watchers

To add watchers that watch nested data in reactive properties, we can set the deep option to true .

For instance, we can write:

<template>
  <div>{{ person }}</div>
</template>

<script>
export default {
  name: "App",
  watch: {
    person: {
      deep: true,
      immediate: true,
      handler(val) {
        console.log(val);
      },
    },
  },
  data() {
    return {
      person: {
        firstName: "jane",
        lastName: "smith",
      },
    };
  },
};
</script>

to watch the person object.

We set deep to true to run the handler method whenever any property in it changes.

The immediate property is set to true to the handler method to run when the person initial value is set.

Therefore, we should see the console.log method log the val value when we set the person reactive property.

Also, we can watch any single property in an object for changes.

For instance, we can write:

<template>
  <div>{{ person }}</div>
</template>

<script>
export default {
  name: "App",
  watch: {
    "person.firstName": {
      immediate: true,
      handler(val) {
        console.log(val);
      },
    },
  },
  data() {
    return {
      person: {
        firstName: "jane",
        lastName: "smith",
      },
    };
  },
};
</script>

We have the “person.firstName” watcher to watch the person.firstName value for changes.

Then the val parameter should log the value of person.firstName , which is 'jane' .

Conclusion

We can watch for nested data in reactive properties easily with watchers in Vue 3.

Categories
Vue 3

How to Build a Tab Component with Vue.js 3?

Sometimes, we may want to display things in tabs.

In this article, we’ll look at how to build a tab component with Vue 3.

Build a Tab Component with Vue.js 3

We can build a tab component easily with Vue 3’s dynamic component feature.

To use it, we can use the keep-alive and component components.

For instance, we can write:

`<template>
  <button @click="currentTabComponent = 'Tab1'">tab 1</button>
  <button @click="currentTabComponent = 'Tab2'">tab 2</button>
  <button @click="currentTabComponent = 'Tab3'">tab 3</button>
  <keep-alive>
    <component :is="currentTabComponent"></component>
  </keep-alive>
</template>

<script>
import Tab1 from "./components/Tab1.vue";
import Tab2 from "./components/Tab2.vue";
import Tab3 from "./components/Tab3.vue";

export default {
  name: "App",
  components: {
    Tab1,
    Tab2,
    Tab3,
  },
  data() {
    return {
      currentTabComponent: "Tab1",
    };
  },
};
</script>

components/Tab1.vue

<template>
  <div>tab 1</div>
</template>

components/Tab2.vue

<template>
  <div>tab 2</div>
</template>

components/Tab3.vue

<template>
  <div>tab 3</div>
</template>

In App.vue , we have 3 buttons that sets the currentTab component value to the tag name for the component to show.

Then we have the keep-alive component to prevent unmounting of the dynamic components.

The component component lets us set which component to display dynamically.

The is prop takes a string with the tag name of the component to display.

Next, we register the components in the compoennts property.

Then in data we return the currentTabComponent set to 'Tab1' , which is the name of the component tag for the component we want to display initially.

Then in Tab1.vue , Tab2.vue and Tab3.vue , we render the tab contents.

Now when we click on each button, we should see different content displayed below it.

Conclusion

We can add tabs easily into a Vue 3 app with the keep-alive and component components.

Categories
Vue 3

How to Build a Datepicker Component with Vue.js 3?

Sometimes, we want to build our own date picker component in our Vue 3 app to let users select a date.

In this article, we’ll look at how to build a date picker component with Vue 3.

Build a Datepicker Component with Vue.js 3

We can build our own input component by creating a component that takes the modelValue prop and emits the update:modelValue event.

The 2 things together is the same as the v-model directive.

So we can write the following code to create a date picker and use it.

App.vue

<template>
  <DatePicker v-model="date" />
  <p>{{ date }}</p>
</template>

<script>
import DatePicker from "./components/DatePicker.vue";

export default {
  name: "App",
  components: {
    DatePicker,
  },
  data() {
    return {
      date: new Date(2020, 1, 1),
    };
  },
};
</script>

components/DatePicker.vue

<template>
  <div id="date-picker">
    <div>
      <label>year</label>
      <br />
      <select v-model="year">
        <option v-for="y in years" :key="y">
          {{ y }}
        </option>
      </select>
    </div>
    <div>
      <label>month</label>
      <br />
      <select v-model="month">
        <option v-for="m in 12" :key="m" :value="m - 1">
          {{ m }}
        </option>
      </select>
    </div>
    <div>
      <label>day</label>
      <br />
      <select v-model="day">
        <option v-for="d in maxDate" :key="d">
          {{ d }}
        </option>
      </select>
    </div>
  </div>
</template>

<style scoped>
#date-picker {
  display: flex;
}

#date-picker div {
  margin-right: 10px;
}
</style>

<script>
import moment from "moment";

export default {
  name: "DatePicker",
  props: {
    modelValue: Date,
  },
  data() {
    return {
      years: [],
      year: new Date().getFullYear(),
      month: 0,
      day: 1,
    };
  },
  methods: {
    emitDate() {
      const { year, month, day } = this;
      this.$emit("update:modelValue", new Date(year, month, day).toString());
    },
  },
  watch: {
    year() {
      this.emitDate();
    },
    month() {
      this.emitDate();
    },
    day() {
      this.emitDate();
    },
  },
  computed: {
    maxDate() {
      const { month } = this;
      if ([0, 2, 4, 6, 7, 9, 11].includes(month)) {
        return 31;
      } else if ([3, 5, 8, 10].includes(month)) {
        return 30;
      }
      return 28;
    },
  },
  beforeMount() {
    const currentYear = new Date().getFullYear();
    for (let i = -100; i <= 100; i++) {
      this.years.push(currentYear + i);
    }
    const d = moment(this.modelValue);
    this.year = +d.format("YYYY");
    this.month = +d.format("MM") - 1;
    this.day = +d.format("DD");
  },
};
</script>

In App.vue , we add the DatePicker component and bind it to a date string with v-model .

We create the date string with the Date constructor.

It’ll be converted to a string automatically when we get it from the modelValue prop.

Below that, we show the date value.

Then in DatePicker.vue , we add the 3 select elements to let us pick the year, month, and day.

We bind the select element value to reactive properties with v-model .

The value for the month starts with 0 and ends with 11 to match what the Date constructor accepts.

We use v-for to render the numbers for the value for the options.

Next, we add some styles to the style tag to make the dropdowns display side by side and add margins between them.

Then we have the component object.

The component takes the modelValue prop which is a string.

data returns the reactive properties we use for the template.

years is an array of years for the year dropdown which we’ll populate later.

year , month , and day are set to default values.

Next, we have the emitDate method to emit the update:modelValue event with the date string.

We call it in the year , month , and day watchers so it’ll run when any of these values change.

Then we add the maxDate computed property to return the max day we can set according to which month is chosen.

Since JavaScript Date constructor takes months that are 0 based, we check month values from 0 to 11, where 0 is January and 11 is December.

Finally, in the beforeMount hook, we populate the years array with 100 years before and after the current year.

And we get the modelValue prop’s value and parse the year, month, and day values

We do the parsing with the format method that comes with moment objects.

Now when we change the options in the drop-down, we should see the choices reflect in the text below.

Conclusion

We can create a drop-down component easily with Vue 3.