You may have heard of filters if you have come from using Vue 2.x but to get straight to the point, they have been removed and can no longer be used in Vue 3.x, as covered by the migration guide.
If you were a fan of using filters, this might be a little disappointing as they provided a convenient way to format values before they were made visible to the user without writing more JavaScript.
All is not lost, however. Continue reading, and I'll show you a couple of alternatives for restoring filters in your Vue 3.x projects.
What Are Filters?
For those who aren't entirely familiar with filters, what are they? Or rather, what were they? In Vue 2.x you could define a filter accessible via your HTML, for example.
<template>
<!-- Hello, Bob -->
<p>Hello, {{ name | ucfirst }}</p>
</template>
<script>
export default {
data: function() {
return {
name: 'bob',
}
}
filters: {
ucfirst(value) {
return value.substr(0, 1).toUpperCase() + value.substr(1);
}
}
}
</script>
Notice the pipe separating the variable from the filter name (ucfirst
). I defined a filter called ucfirst
that takes the value and uppercases the first letter in the string. By using the pipe separator, we can call these filters on-demand within the HTML.
You could also write these to be globally available in your Vue app and would be handy for presenting human-friendly values, particularly if you wanted to format dates.
Vue 3.x Alternatives to 2.x Filters
Using Computed/Methods
As the official documentation recommends, you can replace your filters with a computed method instead. This way was always an option in Vue 2.x but you probably avoided them for the convenience of using filters in the first place.
This example reuses the one from above, except the syntax is written for 3.x and updated to show both a computed and method example.
<template>
<!-- Using a method -->
{{ ucfirst(name) }}
or
<!-- Using computed -->
{{ formattedName }}
<template>
<script setup>
import { ref, computed } from 'vue';
const name = ref('bob');
// Using computed
const formattedName = computed(() => name.value.substr(0, 1).toUpperCase() + name.value.substr(1));
// Using a method
const ucfirst = (value) => value.substr(0, 1).toUpperCase() + value.substr(1);
</script>
Notice how we're no longer using a pipe to call these and instead either referencing a value directly or through a method.
The downside is that we have to redefine these for every component they are used in, as they are not globally imported which moves us onto the next two solutions.
Reusable Methods Across Components
This further expands on the previous solution as it starts with the same structure where we move the filters into a computed/method call. If we want to make these reusable across components then we need to separate them and import them as modules.
Taking the formattedName
example from above, let's extract the logic into its own file and export it. We'll then import it into our component file and make a few adjustments.
Step 1: Create a Helpers File
Create a new file utils/helpers.js
in your project. Move the logic for the ucfirst
method into the file and make sure to export the function so we can import it later.
Step 2: Import The Helpers File
Import the ucfirst
function from our helpers file into our previous component and adapt the computed to call the method.
<template>
{{ formattedName }}
<template>
<script setup>
import { ref, computed } from 'vue';
import { ucfirst } from '@/utils/helpers.js';
const name = ref('bob');
const formattedName = computed(() => ucfirst(name.value);
</script>
Now we've made part of our logic reusable and the ucfirst
function can be imported into any component that requires it. I happened to name it helpers.js per my preference but you can split these up as how you see fit.
If you're still after a solution that doesn't require repeating code or handling imports, then let's take a look at a third solution.
Using Global Properties
One of the benefits of filters is you can make them available globally, making them super convenient to use. Since Vue 3.x no longer offers this, we can look to Global Properties instead.
const app = createApp(App);
app.config.globalProperties.$filters = {
formattedName(value) {
return value.substr(0, 1).toUpperCase() + value.substr(1))
}
}
Then from within your HTML you can access the filter directly via the global $filters
property we just created above.
<p>{{ $filters.formattedName(name) }}</p>
Now it's not quite as fluent as it was in Vue 2.x and if you are migrating a Vue 2.x project to Vue 3.x then you still have some work to do. However, this is the closest one gets to filters in Vue 3.x.
The downside is you are locking in the logic of your filters to inside the Vue app, which is why the modular approach may be more ideal.
Conclusion
It is a shame that Vue 3 took away the ability to use filters but we can mimic them in a few ways as shown above. I grew to favour the modular approach as it allows the code to be reused as more than simply filters, or outside of Vue entirely.