Telerik blogs

Let’s explore the reasons behind moving away from filters and how Vue 3 encourages alternative ways for achieving the same functionality.

Vue 3 officially launched in September 2020, and support for its predecessor, Vue 2, ended in December 2023. One significant shift in Vue 3 was the deprecation of filters, a feature commonly used in Vue 2 for formatting text and numbers within templates.

In this article, we’ll explore the reasons behind moving away from filters and how Vue 3 encourages alternative ways for achieving the same functionality.

Filters in Vue 2

In Vue 2, filters were primarily used to apply common text formatting directly in the template, such as capitalizing strings, formatting dates or adjusting number precision. Filters could be applied locally or globally and were used by chaining them in the template expressions with a pipe (|) symbol. For example:

<template>
  <p>{{ message | capitalize }}</p>
</template>

In the above example, capitalize could be a custom filter that capitalizes the first letter of the message data string.

<template>
  <p>{{ message | capitalize }}</p>
</template>

<script>
  export default {
    data: {
      message: 'hello world',
    }
    filters: {
      capitalize(value) {
        return value.toUpperCase();
      }
    }
  }
</script>

While filters like the above provided a convenient way to handle formatting issues directly in templates, they had limitations, especially concerning their reusability and composability across components. Furthermore, the Vue migration documentation notes that while filters do appear to be a convenience, they require a custom syntax that breaks the assumption of expressions inside curly braces being “just JavaScript,” which has both learning and implementation costs.

Moving Away from Filters in Vue 3

To achieve the same functionality as filters in Vue 3, the Vue migration documentation recommends replacing them with either method calls or computed properties.

Using Computed Properties

Computed properties are ideal for transforming data based on reactive dependencies. Computed properties are cached based on the dependencies they depend on and only re-evaluate when some of their dependencies have changed. Here is an example of replacing the capitalize filter example we shared above with a computed property named capitalizedMessage:

<template>
  <p>{{ capitalizedMessage }}</p>
</template>

<script setup>
  import { computed } from "vue";

  const message = ref("hello world");

  const capitalizedMessage = computed(() => {
    return message.value.toUpperCase();
  });
</script>

In the above example, the capitalizedMessage computed property takes the message ref as a dependency and transforms its value to uppercase.

Using Methods

For non-reactive or one-time data transformations, methods can be used in place of computed properties. This approach is similar to using filters, but methods have to be invoked explicitly in the template:

<template>
  <p>{{ capitalize(message) }}</p>
</template>

<script setup>
  const capitalize = (value) => {
    return value.toUpperCase();
  };
</script>

In the above example, the formatMessage() method takes a value as input and transforms it to uppercase. This method can be invoked explicitly in the template by passing the message value as an argument within the {{ }} interpolation syntax. This approach is suitable for non-reactive or one-time data transformations, providing similar functionality to filters in Vue 2.

Migrating Global Filters

In Vue 2, global filters could be created to define reusable filters that could be accessed from any component within an application. Here’s how we might have set up a global filter in Vue 2, using the capitalize filter as an example:

import Vue from "vue";

Vue.filter("capitalize", function (value) {
  return value.toUpperCase();
});

const app = new Vue({
  el: "#app",
});

Migrating global filters to methods and computed properties that are to be defined in every component that uses the filter won’t be straightforward. In cases like this, the Vue migration documentation encourages making global filters available to all components through globalProperties. This allows us to define global properties or methods that are accessible throughout our Vue application.

Here’s an example of defining a capitalize() method as a global property under a $filters object.

import { createApp } from "vue";

const app = createApp({});

app.config.globalProperties.$filters = {
  capitalize(value) {
    return value.toUpperCase();
  },
};

app.mount("#app");

With this approach, the capitalize() method becomes accessible as $filters.capitalize() in any component of our Vue application.

<template>
  <div>
    <p>{{ message }}</p>
    <p>{{ $filters.capitalize(message) }}</p>
  </div>
</template>

<script setup>
  import { ref } from "vue";

  const message = ref("hello world");
</script>

Wrap-up

By deprecating filters and encouraging the use of computed properties and methods, this change has helped improve the Vue framework’s overall consistency and reactivity. Computed properties offer a robust solution for reactive data transformations, optimizing performance by re-evaluating only when necessary, while methods provide flexibility for more straightforward, non-reactive transformations.

For more details, be sure to check Vue’s migration guide on filters.


About the Author

Hassan Djirdeh

Hassan is a senior frontend engineer and has helped build large production applications at-scale at organizations like Doordash, Instacart and Shopify. Hassan is also a published author and course instructor where he’s helped thousands of students learn in-depth frontend engineering skills like React, Vue, TypeScript, and GraphQL.

Related Posts

Comments

Comments are disabled in preview mode.