adam78
adam78

Reputation: 10068

Vue.js computed property not working

I have a users data object which has a first_name and last_name and a computed property which returns the full name but the following doesnt seems to work in my v-for directive?

new Vue({

        el: '#content',

        data: {
          "users": [
            {
              "id": 3,
              "first_name": "Joe",
              "last_name": "Blogs"
            },
            {
              "id": 3,
              "first_name": "Jane",
              "last_name": "Doe"
            }
          ]
       },
        computed: {
           fullName: function (user) {
                return user.first_name + ' ' + user.last_name;
            }

        }

    });



    <tr v-for="user in users | orderBy fullName(user)">
          <td class="col-xs-6 col-sm-3 col-md-3 col-lg-3">
              {{fullName(user)}} 
         </td>
    <tr>

Upvotes: 27

Views: 71963

Answers (7)

Azeame
Azeame

Reputation: 2401

I don't believe that a computed property in Vue.js can accept an argument, they are supposed to be able to build themselves without additional interaction. I believe that your fault was that you wrote a method and then tried to register it as a computed property.

So it should be a simple fix to just change the registration of your function from computed to methods which it really is.

methods: {
       fullName: function (user) {
            return user.first_name + ' ' + user.last_name;
        }

    }

This way you will not have to change any of your other code.

Upvotes: 36

laffuste
laffuste

Reputation: 17085

Another reason: properties with an underscore (_) prefix will not trigger computed.

Surprise: _ and $ prefixes are reserved in Vue.

Upvotes: 1

Hans Yulian
Hans Yulian

Reputation: 1170

I have a similar question here: How to dinamically make computed in Vue.js, under dynamically loaded data.

But, in the end here is the possible solution for you from the conclusion that i get after discussing and trial and error. There are several ways:

  1. create extender that assign the computed inside each element, then call it using item.computedProperty() in the UI (with double bracket)
  2. assume the data is loaded, for example items, create a watcher that will assign the computed to each of the element, then put inside extendedItems. the computed function will become reactive when bound to UI, so the UI then will use extendedItems instead of items
  3. use vue's this.$set to manually set and enable reactivity to the computed.

This is using computed with function from the solution number 1:

new Vue({

    el: '#content',

    data: {
      "users": [
        {
          "id": 3,
          "first_name": "Joe",
          "last_name": "Blogs"
        },
        {
          "id": 3,
          "first_name": "Jane",
          "last_name": "Doe"
        }
      ]
   },
    computed: {
        extendedUsers: function(){
            var users = this.users;
            for (var i in users)
                this.extendUser(users[i])

        },
        extendUser: function(user){
            user.fullName = function(){
                return user.first_name + " " + user.last_name;
            }
        }

    }

});



<tr v-for="user in users | orderBy user.fullName()">
      <td class="col-xs-6 col-sm-3 col-md-3 col-lg-3">
          {{user.fullName()}} 
     </td>
<tr>

Upvotes: 0

i had a similar case, when i use a props property with undecleared nested properties. For some reason i made this work doing a

console.log(user.first_name)

       fullName: function (user) {
            console.log(user.first_name)
            return user.first_name + ' ' + user.last_name;
       }

Also, i made this work using lambda expression https://stackoverflow.com/a/46234335/726751

computed: {
    fullName: _this => {
        return _this.user.first_name + ' ' + _this.user.last_name;
    }
}

Upvotes: 1

Mali Naeemi
Mali Naeemi

Reputation: 167

You can map the users in your computed property and use that mapped array like this:

computed: {
  fullName: function () {
    return this.users.map(
      item => item.first_name + ' ' + item.last_name
    );
  }
}

Then in view you can do something like:

<tr v-for="(user, item) in users">
   <td class="col-xs-6 col-sm-3 col-md-3 col-lg-3">
     {{fullName[item]}} 
   </td>
<tr>

And I am using es6 arrow function. If you don't want to use arrow function then you can do something like:

return this.users.map(
  function(item) {return item.first_name + ' ' +item.last_name}
);

Upvotes: 2

Fernanda Lemos
Fernanda Lemos

Reputation: 247

Try to disable cache on the computed property, like mentioned in https://github.com/vuejs/vue/issues/1189. Doing this, the computed value will be always recalculated.

computed: {
  fullName: {
    cache: false,
    get() {
      return user.first_name + ' ' + user.last_name;
    }
  }
}

Upvotes: 23

ceejayoz
ceejayoz

Reputation: 179994

Computed properties don't support nesting like that.

Proof and some workarounds/alternative solutions: https://github.com/vuejs/vue/issues/66

Upvotes: 3

Related Questions