259

is this possible to pass parameter in computed properties in Vue.Js. I can see when having getters/setter using computed, they can take a parameter and assign it to a variable. like here from documentation:

// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

Is this also possible:

// ...
computed: {
  fullName: function (salut) {
      return salut + ' ' + this.firstName + ' ' + this.lastName    
  }
}
// ...

Where computed property takes a argument and returns desired output. However when I try this, I am getting this error:

vue.common.js:2250 Uncaught TypeError: fullName is not a function(…)

Should I be using methods for such cases?

Community
  • 1
  • 1
Saurabh
  • 58,805
  • 34
  • 169
  • 222
  • 8
    No, you can't pass parameters to computed properties. Yes, using methods is the easiest way of doing it. – nils Nov 10 '16 at 08:41

9 Answers9

355

Most probably you want to use a method

<span>{{ fullName('Hi') }}</span>

methods: {
  fullName(salut) {
      return `${salut} ${this.firstName} ${this.lastName}`
  }
}

Longer explanation

Technically you can use a computed property with a parameter like this:

computed: {
   fullName() {
      return salut => `${salut} ${this.firstName} ${this.lastName}`
   }
}

(Thanks Unirgy for the base code for this.)

The difference between a computed property and a method is that computed properties are cached and change only when their dependencies change. A method will evaluate every time it's called.

If you need parameters, there are usually no benefits of using a computed property function over a method in such a case. Though it allows you to have a parametrized getter function bound to the Vue instance, you lose caching so not really any gain there, in fact, you may break reactivity (AFAIU). You can read more about this in Vue documentation https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods

The only useful situation is when you have to use a getter and need to have it parametrized. For instance, this situation happens in Vuex. In Vuex it's the only way to synchronously get parametrized result from the store (actions are async). Thus this approach is listed by official Vuex documentation for its getters https://vuex.vuejs.org/guide/getters.html#method-style-access

orionrush
  • 478
  • 4
  • 27
damienix
  • 5,293
  • 1
  • 20
  • 29
35

You can use methods, but I prefer still to use computed properties instead of methods, if they're not mutating data or do not have external effects.

You can pass arguments to computed properties this way (not documented, but suggested by maintainers, don't remember where):

computed: {
   fullName: function () {
      var vm = this;
      return function (salut) {
          return salut + ' ' + vm.firstName + ' ' + vm.lastName;  
      };
   }
}

EDIT: Please do not use this solution, it only complicates code without any benefits.

Unirgy
  • 1,335
  • 11
  • 24
  • It will be really helpful if you can provide a reference. This should work. – Saurabh Jan 05 '17 at 03:18
  • @saurabh sorry it was a solution for a not really descriptive issue in github, and i can't find it right now... – Unirgy Jan 05 '17 at 04:13
  • This works for me, but the only thing I'm not a fan of is the fact that it returns a function rather than the actual property, so the VueJS devtools doesn't show the results anywhere. I'm not sure if that's typical for computed properties, but it makes troubleshooting a little harder. – Nate Ritter Jan 19 '17 at 19:39
  • 4
    How does it handle caching? Will it work properly when the parameter changes? – damienix Apr 05 '17 at 14:44
  • I don't believe it would cache anything inside the return function. The difference from methods would be purely of convention (methods have effect, computed are only for retrieval) – Unirgy Jun 22 '17 at 23:36
  • Though this is a smart approach, I would advise to just go with a method in this case. – Juan May 12 '18 at 22:29
  • @damienix It won't cache. There is no benefit to using a computed property like this. You should use a method. If you need a method to be reactively triggered then you should use it in conjunction with a watcher. – James Jun 25 '18 at 00:59
  • It was helpful for me , as in my case i had to pass parameters to the computed property , because functions would call only once , but for me data is bind like this and have a computed property like getNetSales(key) on another loop , and any change to sales index needs getNetSales to change. – JIJO JOSEPH Dec 16 '20 at 18:31
12

Well, technically speaking we can pass a parameter to a computed function, the same way we can pass a parameter to a getter function in vuex. Such a function is a function that returns a function.

For instance, in the getters of a store:

{
  itemById: function(state) {
    return (id) => state.itemPool[id];
  }
}

This getter can be mapped to the computed functions of a component:

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ])
}

And we can use this computed function in our template as follows:

<div v-for="id in ids" :key="id">{{itemById(id).description}}</div>

We can apply the same approach to create a computed method that takes a parameter.

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ]),
  descriptionById: function() {
    return (id) => this.itemById(id).description;
  }
}

And use it in our template:

<div v-for="id in ids" :key="id">{{descriptionById(id)}}</div>

This being said, I'm not saying here that it's the right way of doing things with Vue.

However, I could observe that when the item with the specified ID is mutated in the store, the view does refresh its contents automatically with the new properties of this item (the binding seems to be working just fine).

Stéphane Appercel
  • 1,367
  • 2
  • 12
  • 18
  • woah so this worked for me , not using vuex . would also like to know if this is a legit way to do computed properties. – yeahdixon Apr 19 '18 at 15:17
  • 3
    Whilst this does work, it essentially treats the computed property the same as a method. i.e. it loses the caching benefits of a computed property. So, there is no actual gain using this over a method. "Note that getters accessed via methods will run each time you call them, and the result is not cached." See https://vuex.vuejs.org/en/getters.html – James Apr 27 '18 at 05:25
  • @james.brndwgn but I'm pretty sure methods won't be rerun when the underlying data is changed. That's all I'm really looking for. – Alex Jun 24 '18 at 14:03
  • @Alex then you should be using a watcher. https://vuejs.org/v2/guide/computed.html#Watchers – James Jun 25 '18 at 00:55
  • @james.brndwgn I'd much rather use a computed property than a watcher if possible. I was only taking issue with your statement: "So, there is no actual gain using this over a method." as there is a significant difference even without caching. – Alex Jun 26 '18 at 17:10
  • @Alex "as there is a significant difference even without caching" - how so? – James Jul 09 '18 at 03:13
  • @james.brndwgn the computed property gets recomputed when the underlying data changes, the method does not. Meaning you have to trigger the method call on a watcher if you want the same functionality. – Alex Jul 18 '18 at 15:50
  • @alex Yes, this is true of the standard concept of computed properties, but when used in this fashion it will always recalculate as it doesn't know anything about the underlying data. At least with a watcher you can compare the old and new values and only run the method if it meets certain requirements. I would also argue that it's more explicit as to what the intention is when using a watcher & method for this purpose vs a computed property that isn't actually providing the benefits of a computed prop. But that comes down to the experience you want to provide your fellow developers. – James Jul 23 '18 at 03:03
  • ^ This! Thank you. I mean at least I came for this. Docs: https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper – Denis Dec 08 '19 at 21:04
6

Filters are a functionality provided by Vue components that let you apply formatting and transformations to any part of your template dynamic data.

They don’t change a component’s data or anything, but they only affect the output.

Say you are printing a name:

new Vue({
  el: '#container',
  data() {
    return {
      name: 'Maria',
      lastname: 'Silva'
    }
  },
  filters: {
    prepend: (name, lastname, prefix) => {
      return `${prefix} ${name} ${lastname}`
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="container">
  <p>{{ name, lastname | prepend('Hello') }}!</p>
</div>

Notice the syntax to apply a filter, which is | filterName. If you're familiar with Unix, that's the Unix pipe operator, which is used to pass the output of an operation as an input to the next one.

The filters property of the component is an object. A single filter is a function that accepts a value and returns another value.

The returned value is the one that’s actually printed in the Vue.js template.

Diego Pereira
  • 341
  • 3
  • 6
5

You can pass parameters but either it is not a vue.js way or the way you are doing is wrong.

However there are cases when you need to do so.I am going to show you a simple example passing value to computed property using getter and setter.

<template>
    <div>
        Your name is {{get_name}} <!-- John Doe at the beginning -->
        <button @click="name = 'Roland'">Change it</button>
    </div>
</template>

And the script

export default {
    data: () => ({
        name: 'John Doe'
    }),
    computed:{
        get_name: {
            get () {
                return this.name
            },
            set (new_name) {
                this.name = new_name
            }
        },
    }    
}

When the button clicked we are passing to computed property the name 'Roland' and in set() we are changing the name from 'John Doe' to 'Roland'.

Below there is a common use case when computed is used with getter and setter. Say you have the follow vuex store:

export default new Vuex.Store({
  state: {
    name: 'John Doe'
  },
  getters: {
    get_name: state => state.name
  },
  mutations: {
    set_name: (state, payload) => state.name = payload
  },
})

And in your component you want to add v-model to an input but using the vuex store.

<template>
    <div>
        <input type="text" v-model="get_name">
        {{get_name}}
    </div>
</template>
<script>
export default {
    computed:{
        get_name: {
            get () {
                return this.$store.getters.get_name
            },
            set (new_name) {
                this.$store.commit('set_name', new_name)
            }
        },
    }    
}
</script>
roli roli
  • 14,330
  • 3
  • 58
  • 70
5

You can also pass arguments to getters by returning a function. This is particularly useful when you want to query an array in the store:

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

Note that getters accessed via methods will run each time you call them, and the result is not cached.

That is called Method-Style Access and it is documented on the Vue.js docs.

Vini Brasil
  • 4,828
  • 3
  • 22
  • 31
5
computed: {
  fullName: (app)=> (salut)=> {
      return salut + ' ' + this.firstName + ' ' + this.lastName    
  }
}

when you want use

<p>{{fullName('your salut')}}</p>
Khalid Hasan
  • 89
  • 1
  • 5
1

Computed could be consider has a function. So for an exemple on valdiation you could clearly do something like :

    methods: {
        validation(attr){
            switch(attr) {
                case 'email':
                    const re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
                    return re.test(this.form.email);
                case 'password':
                    return this.form.password.length > 4
            }
        },
        ...
    }

Which you'll be using like :

  <b-form-input
            id="email"
            v-model="form.email"
            type="email"
            :state="validation('email')"
            required
            placeholder="Enter email"
    ></b-form-input>

Just keep in mind that you will still miss the caching specific to computed.

Baldráni
  • 4,066
  • 3
  • 41
  • 63
0

Yes methods are there for using params. Like answers stated above, in your example it's best to use methods since execution is very light.

Only for reference, in a situation where the method is complex and cost is high, you can cache the results like so:

data() {
    return {
        fullNameCache:{}
    };
}

methods: {
    fullName(salut) {
        if (!this.fullNameCache[salut]) {
            this.fullNameCache[salut] = salut + ' ' + this.firstName + ' ' + this.lastName;
        }
        return this.fullNameCache[salut];
    }
}

note: When using this, watchout for memory if dealing with thousands

Isometriq
  • 191
  • 1
  • 7