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.

Categories
Vue

How to Listen for Props Changes in a Vue.js Component?

Listening for prop changes is something that we’ve to do often in Vue.js components.

In this article, we’ll look at how to listen for prop changes in our Vue.js components.

Watchers

Props are reactive, so we can watch for value changes with watchers.

To do this, we write:

App.vue

<template>
  <div id="app">
    <HelloWorld :name="name" />
    <button @click="name = name === 'james' ? 'jane' : 'james'">
      Change text
    </button>
  </div>
</template>

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

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

components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    name: String,
  },
  watch: {
    name(val) {
      console.log(val);
    },
  },
};
</script>

In App.vue , we have the name state which we pass into the HelloWorld component via the name prop.

Also, we have a button that changes the name state value when we click it.

Then in the HelloWorld component, we register the name prop with the props property.

And we watch the name prop with the watch property with name added inside it.

name is set to a method with the val parameter that lets us get the current value of the name prop.

Therefore, when we click Change text, we see the latest value of the name prop logged.

It should be consistent with the name value on the template.

We can also get the previous value of a prop with the second parameter of the watcher function.

For instance, we can write:

components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    name: String,
  },
  watch: {
    name(val, oldVal) {
      console.log(val, oldVal);
    },
  },
};
</script>

App.vue stays the same.

oldVal has the previous value of the name prop.

Therefore, we should see the current and previous value of the name prop logged when we click the Change text button.

We can also add the deep property to watch for deeply nested properties of an object prop.

And the immediately property set to true will watch initial value of the prop.

For instance, we can write:

<template>
  <div class="hello">
    <h1>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    name: String,
  },
  watch: {
    deep: true,
    immediate: true,
    name(val, oldVal) {
      console.log(val, oldVal);
    },
  },
};
</script>

We set them both to true so we can watch deeply nested properties and the initial value.

Conclusion

We can listen for prop changes within a Vue.js component with a watcher.

Categories
Vue

How to Get Query Parameters from a URL in Vue.js?

Getting query parameters from a URL is something that we’ve to do often in our Vue.js apps.

In this article, we’ll look at how to get query parameters from a URL in Vue.js.

Get Query Parameters from a URL

With Vue Router, we can get a query parameter in a route component’s URL easily.

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
});

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>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      name: "",
    };
  },
  mounted() {
    this.name = this.$route.query.name;
  },
};
</script>

In main.js , we defined the routes that we can load with Vue Router in the routes array.

Then we call Vue.use(VueRouter) so that the dependencies like router-view and extra properties for components are added.

Next, we create the VueRouter instance with the routes .

And we pass the router into the Vue instance object to register the routes.

We get the name query parameter as we did in views/HelloWorld.vue .

this.$router.query.name has the value of the name query parameter.

Therefore, when we go to /#/hello?name=james, we see ‘hi, james’ displayed since we assigned it to this.name .

Another way to get the query string is to pass it in as props.

To do this, we 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,
    props: (route) => ({ name: route.query.name })
  }
];

Vue.config.productionTip = false;
Vue.use(VueRouter);

const router = new VueRouter({
  routes
});

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

Then we change views/HelloWorld.vue to:

<template>
  <div class="hello">
    <h1>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    name: String,
  },
};
</script>

And App.vue stays the same.

The props property is set to a function that takes the route parameter.

And we return an object with the name property set to route.query.name .

In HelloWorld.vue , we register the name prop with the props property and display name directly in the template.

Therefore, when we go to /#/hello?name=james, we see ‘hi, james’ again.

URLSearchParams

If we don’t use Vue Router, then we can get the query parameter with the URLSearchParams constructor.

For instance, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

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

App.vue

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

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

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

components/HelloWorld.vue

<template>
  <div class="hello">
    <h1>hi, {{ name }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      name: "",
    };
  },
  mounted() {
    const urlParams = new URLSearchParams(window.location.search);
    this.name = urlParams.get("name");
  },
};
</script>

We call the URLSearchParams constructor with window.location.search , which has the query string.

Then we can get the query parameter with the given key with urlParams.get .

We assigned it to this.name so we can use it in the template.

So if we go to /?name=james , we see ‘hi, james’ displayed.

Conclusion

We can get URL parameters within a component with or without Vue Router.

Categories
Vue

How to Properly Watch for Nested Data with Vue.js

Watching for deeply nested object states and props is something that we often have to do in a Vue.js app.

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

Deep Watchers

We can add deep watchers to components within the watch property.

For instance, we can write:

App.vue

<template>
  <div id="app">
    <button
      @click="
        id++;
        getTodo(id);
      "
    >
      increment id
    </button>
    <Todo :todo="todo" />
  </div>
</template>

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

export default {
  name: "App",
  components: {
    Todo,
  },
  data() {
    return {
      todo: {},
      id: 1,
    };
  },
  methods: {
    async getTodo(id) {
      const results = await fetch(
        `https://jsonplaceholder.typicode.com/todos/${id}`
      );
      const data = await results.json();
      this.todo = data;
    },
  },
};
</script>

Todo.vue

<template>
  <div class="hello"></div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todo: Object,
  },
  watch: {
    todo: {
      handler(val) {
        console.log(val);
      },
      deep: true,
    },
  },
};
</script>

We have a button that calls getTodo when we get it to get a new todo object with the given id .

getTodo updates the todo reactive property from the response.

We pass the todo value to the todo prop of the Todo component.

Then in the Todo component, we watch the todo prop with the watch property.

We have the handler function with the val parameter to get the latest value.

deep is set to true so that we can watch for properties object props.

Computed Property

We can create a computed property to get the property from a reactive property.

For instance, we can write:

Todo.vue

<template>
  <div>{{ todoTitle }}</div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todo: Object,
  },
  computed: {
    todoTitle() {
      return this.todo.title;
    },
  },
};
</script>

We keep App.vue the same.

We created the todoTitle computed property that returns the this.todo.title property.

Then we can use it in the template like any other reactive property.

todoTitle will be updated whenever any property in the this.todo object is updated.

Watch a Property of an Object

We can also watch a property of an object.

For instance, we can write:

<template>
  <div class="hello"></div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todo: Object,
  },
  watch: {
    "todo.title": {
      handler(val) {
        console.log(val);
      },
    },
  },
};
</script>

Then the title property from the todo prop is watched with the watcher.

This is because 'todo.title' is the title property of the todo prop.

val would have the value of the title property of the todo prop.

We can get the newVal and oldVal from the watcher function:

<template>
  <div class="hello"></div>
</template>

<script>
export default {
  name: "Todo",
  props: {
    todo: Object,
  },
  watch: {
    "todo.title": {
      handler(newVal, oldVal) {
        console.log(newVal, oldVal);
      },
    },
  },
};
</script>

Conclusion

We can watch for nested properties with watchers by adding methods to the watch property object with a property path.

Also, we can set deep to true to watch for deeply nested properties.

Categories
React

How to Focus Something on Next Render with React Hooks?

We may want to focus something on the next render within a component created with React hooks.

In this article, we’ll look at how to focus on an element on the next render within a component created with React hooks.

Focus Something on Next Render with React Hooks

To focus on an element on the next render, we can write something like the following:

import { useEffect, useRef, useState } from "react";

export default function App() {
  const [isEditing, setEditing] = useState(false);
  const toggleEditing = () => {
    setEditing(!isEditing);
  };

  const inputRef = useRef(null);

  useEffect(() => {
    if (isEditing) {
      inputRef.current.focus();
    }
  }, [isEditing]);

  return (
    <div>
      {isEditing && <input ref={inputRef} />}
      <button onClick={toggleEditing}>edit</button>
    </div>
  );
}

We create the isEditing state with the useState hook.

It’s set to false initially.

Next, we add the toggleEditing function to call setEditing function to the negated value of the isEditing state.

Then we create the inputRef ref that lets us assign to the input element below.

Next, we have the useEffect hook that runs when the isEditing state is changed.

We check the isEditing value, and if it’s true , we call inputRef.current.focus() to focus on the input.

The 2nd argument is set to [isEditing] so that isEditing ‘s value is watched.

Then we render the input if isEditing is true .

And in the input, we assigned a ref to it.

And we have a button that runs the toggleEditing function when we click on edit.

Conclusion

We can focus on an element on next render easily by watching a state’s value with useEffect .

Then we can check the value of the state and call focus on the element object, which is the ref which we assigned to the element.