Categories
Vue

What’s the Difference between v-model and v-bind Directives in Vue.js?

Vue.js comes with 2 built-in directives that are used often.

They’re the v-model and v-bind directives.

They serve different purposes.

In this article, we’ll look at the differences between the v-model and v-bind directives in Vue.js

v-bind

The v-bind lets us do one-way binding between the parent and child components.

We can pass data from the parent to the child component.

The child component will receive the data as props.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <HelloWorld :name="name" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  data() {
    return {
      name: "jane",
    };
  },
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">hello {{ name }}</div>
</template>
<script>
export default {
  name: "HelloWorld",
  props: {
    name: String,
  },
};
</script>

In the App.vue component, we have the HelloWorld component in the template with the :name directive.

:name is short for v-bind:name .

So we can also write:

<template>
  <div id="app">
    <HelloWorld v-bind:name="name" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  data() {
    return {
      name: "jane",
    };
  },
};
</script>

name is the prop name.

And we set the name reactive property as the value of the name prop.

In HelloWorld.vue , we register the name prop in the props property.

We set the data type of the prop to String .

This is the data type that’s expected to be passed in.

And the value of the name prop isn’t a string, then an error will be logged in the console.

Then we can reference the prop’s value in the template or reference it in the component with this.name .

Therefore, we should see ‘hello jane’ displayed.

v-bind lets us pass data from parent component to the child.

v-model

The v-model directive provides us with 2 way binding between parent and child components.

It’s the equivalent of adding the value prop and emitting the input event.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <CustomInput v-model="name" />
    <p>{{ name }}</p>
  </div>
</template>

<script>
import CustomInput from "./components/CustomInput";

export default {
  name: "App",
  components: {
    CustomInput,
  },
  data() {
    return {
      name: "jane",
    };
  },
};
</script>

components/CustomInput.vue

<template>
  <div>
    <input :value="value" @input="$emit('input', $event.target.value)" />
  </div>
</template>
<script>
export default {
  name: "CustomInput",
  props: {
    value: String,
  },
};
</script>

In App.vue , we have the CustomInput component that’s bound to the name reactive property with v-model .

We display the name value below the CustomInput .

The in the CustomInnput component, we register the value prop.

And we pass the value into value prop of the input element.

Also, we listen for the input event.

And when it’s emitted, we call $emit to emit the input event as indicated in the first argument of emit.

$event.target.value has the inputted value.

Since CustomInput takes the value prop and emits the input event, we can use v-model to add 2-way binding between the 2 components.

And when we type in the input, we see the name value displayed below changes.

We can also write:

<template>
  <div>
    <input :value="value" @input="onInput" />
  </div>
</template>
<script>
export default {
  name: "CustomInput",
  props: {
    value: String,
  },
  methods: {
    onInput(event) {
      this.$emit("input", event.target.value);
    },
  },
};
</script>

in CustomInput.vue .

$emit is the template is the same as this.$emit in the onInput method.

$event.target.value is replaced with event.target.value .

Conclusion

v-bind provides us with one way binding from the parent component to the child.

And v-model provides us with 2-way binding between the parent and child.

Categories
Vue

How to Force Vue.js to Reload or Re-render a Component?

Sometimes we want to force a Vue.js component to reload or re-render a component.

In this article, we’ll look at how to force a Vue.js component to reload or re-render a component.

The forceUpdate Method

One way to force a component to re-render is to use the forceUpdate method.

For instance, we can write:

<template>
  <div id="app">
    <button @click="forceUpdate">force update</button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    forceUpdate() {
      this.$forceUpdate();
    },
  },
};
</script>

to call the $forceUpdate method in our component.

However, a re-rendering is done when we update any reactive property, so the better way to force re-rendering a component is to update reactive properties.

Changing the Component’s Key Prop

We can change the component’s key prop to make the component re-render.

This is because a prop should be set to a reactive property as its value.

And reactive properties changes will make a component re-render.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <HelloWorld :key="key" />
    <button @click="forceUpdate">reload</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  data() {
    return {
      key: 0,
    };
  },
  methods: {
    forceUpdate(name) {
      this.key++;
    },
  },
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">hello world</div>
</template>
<script>
export default {
  name: "HelloWorld",
};
</script>

We have the HelloWorld component with the key prop that is set to the key reactive property.

And we have the forceUpdate method that’s called when we click the reload button.

The key reactive property updates which will force everything in the App component to re-render including the HelloWorld component.

As long as the value of key changes, re-rendering will be done.

Conclusion

We can force a re-render or reload of a component with the $forceUpdate method or updating the key prop of a component.

Categories
Vue

How to Call a Vue.js Component’s Method from Outside the Component?

Calling a Vue.js’s component from outside the component is something that we have to do sometimes.

In this article, we’ll look at how to call one component’s function from another component.

Refs

We can assign a ref to a component and then we can get the whole component object from the ref, including its methods.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <button @click="hello">hello world</button>
    <HelloWorld ref="hello" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  methods: {
    hello() {
      this.$refs.hello.helloWorld();
    },
  },
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>hello world</h1>
  </div>
</template>
<script>
export default {
  name: "HelloWorld",
  methods: {
    helloWorld() {
      alert("hello world");
    },
  },
};
</script>

In App.vue , we have a button that calls the hello method when we click it.

And we have the HelloWorld component that’s assigned the hello ref.

Then we defined the hello method that calls this.$refs.hello.helloWorld method.

In HelloWorld.vue , we defined the helloWorld method.

It’s the same method that’s referenced by this.$refs.hello.helloWorld .

Therefore, when we click on the button, we see ‘hello world’ displayed in the popup.

This works if we want to call a child component’s method from a parent.

Emitting Events

If we want to call a parent component’s method from a child component, we can emit an event to do so.

To emit an event, we use the $emit method.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <HelloWorld [@greet](https://medium.com/r/?url=http%3A%2F%2Ftwitter.com%2Fgreet "Twitter profile for @greet")="hello" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  methods: {
    hello(name) {
      alert(`hello ${name}`);
    },
  },
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">
    <button @click="greet">greet</button>
  </div>
</template>
<script>
export default {
  name: "HelloWorld",
  methods: {
    greet() {
      this.$emit("greet", "jane");
    },
  },
};
</script>

In App.vue , we have the HelloWorld component in the templaye.

We have the @greet directive to listen to the greet event emitted from the HelloWorld component.

It’s set to the hello method as its value, so it’ll be called when we emit the event.

Then we add the hello method with the name parameter.

We get the name parameter and call alert with it.

Then in HelloWorld.vue , we have a button that calls the greet method when we click it.

The greet method calls this.$emit to emit the greet event.

The first argument of the $emit method is the event’s name.

The 2nd argument and beyond are the arguments we want to pass into the method that’s called.

So 'jane' is the value of the name parameter of hello in App.vue .

Therefore, if we click the greet button, we should see ‘hello jane’ displayed in the alert popup.

Conclusion

We can call a child component’s method from a parent component by assigning a ref to the child component.

And then call the child component’s ref’s methods to call them.

If we want to call a method in the parent component from the child, then we emit an event with the parameters we want to call the method with.

Categories
Vue

How to Remove Hashbang from a URL in a Vue.js App?

If we’re using Vue Router, then by default, the URL generated from a component has the hashbang in it.

In this article, we’ll look at how to remove a hashbang from a URL in a Vue.js app.

History Mode

We can remove the hashbang from a URL if we set Vue Router to history mode.

For instance, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import HelloWorld from "./views/HelloWorld.vue";
import VueRouter from "vue-router";

const routes = [{ path: "/hello", component: HelloWorld }];

Vue.config.productionTip = false;

Vue.use(VueRouter);
const router = new VueRouter({
  routes,
  mode: "history"
});

new Vue({
  render: (h) => h(App),
  router
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

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

views/HelloWorld.vue

<template>
  <div class="hello">
    <h1>hello world</h1>
  </div>
</template>
<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      name: "",
    };
  },
};
</script>

In main.js , we create the VueRouter instance with an object that has the routes property.

And also, we have the mode property set to 'history' .

How we can go to the /hello path without the hash.

So instead of going to /#/hello , we go to /hello .

To make this work, the server has to be properly configured.

For example, if we’re using an Apache server, then we’ve configure the server to go to index.html when we go to any URL.

This way, the Vue app will be loaded instead of other things in the server since index.html is the home page of a Vue app if the Vue app is deployed to the server.

For instance, we can write:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>

With Nginx, we configure our server by writing:

location / {
  try_files $uri $uri/ /index.html;
}

Other configs are available at https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations.

Conclusion

We can remove the hashbang from a URL by making Vue Router use history mode instead of the default hash mode.

Categories
Vue

How to Disable Input Conditionally in a Vue.js Component?

Disabling inputs conditionally in a Vue.js component is something that we may have to do sometimes.

In this article, we’ll look at how we can disable inputs conditionally in our Vue.js components.

Disabled Prop

To disable an input conditionally with Vue.js component, we can set the value of the disabled prop.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <input type="text" :disabled="disabled" />
    <button @click="disabled = !disabled">toggle</button>
  </div>
</template>

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

We have the disabled state defined in the object we return in the data method.

Then we have a button that toggles the disabled prop between true and false .

Then in the input, we set the disabled prop to the disabled value.

Now the input will be toggled between enabled and disabled when we click on the toggle button.

We can also pass in a computed property to the disabled prop.

For instance, we can write:

<template>
  <div id="app">
    <input type="text" :disabled="isDisabled" />
    <button @click="count++">increment</button>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      count: 0,
    };
  },
  computed: {
    isDisabled() {
      return this.count === 3;
    },
  },
};
</script>

We have the count state which the isDisabled computed property is derived from.

We return true is this.count is 3.

The increment button increases the count value by 1 each time we click it.

Therefore, when we click increment and the count is set to 3, we see the input disabled.

Conclusion

We can disable input values with the disable prop on the input.

We can set it to a state or a computed property.