Search code examples
javascriptvue.jsvuejs2vue-componentv-for

Vue.js - calculated value from method doesn't display in looped list


I feel like this is a timing thing, but not necessarily an async thing. I am looping through an object and displaying a list of items. For one of the values I need to calculate it with a method.

The values directly on the item object display fine, but the calculated one never shows up, even though I can console.log it and it's there.

I've trying changing keys top to rerender the list but no luck. I tried making it a computed property but ran into "not a function" issues.

<ul>
  <li
    v-for="(item, index) in list"
    :key="index"
    class="list-wrap"
  >
    <span> 
      {{ item.name }} <---- this value shows every time.
    </span>
      <span class="location">
        {{ getLocation(item.Location[0]) }} <---- this "calculated" value returns only sometimes.
      </span>
  </li>
</ul>

getLocation method:

methods: {
  getLocation(loc) { // id coming from item in loop
    this.locations.forEach((location) => { // loop through locations obj, match id, return location name.
      let match;
      if (location.id === loc) {
        match = location.name;
        console.log(match); <---- present / correct on every refresh
        return match; <--- not rendering
      }
    });
  },
},

// list is created in async api call

async getCurUserTransfers() {
  await airtableQuery
    .getTableAsync("Transfers", 100, "Grid view")
    .then((data) => {
      this.list = data.filter( // list is a filtered table.
        (transfer) =>
          transfer.fields.User === this.curUserNicename ||
          transfer.fields.User === this.curUserDisplayName
      );
    });
},

Solution

  • The best practice with calculated fields is using computed property, so you should add a computed one called listWithLocation then loop through it :

    computed:{
         listWithLocation(){
    
         return this.list.map( item=>{
            item.itemLocation=this.getLocation(item.Location[0]);// add field itemLocation and use the method already defined
             return item;
        }) 
    }
    }
    

    template :

    <ul>
      <li
        v-for="(item, index) in listWithLocation"
        :key="index"
        class="list-wrap"
      >
        <span> 
          {{ item.name }} 
        </span>
          <span class="location">
            {{item.itemLocation}}
          </span>
      </li>
    </ul>
    

    the method :

    methods: {
      getLocation(loc) { 
        return this.locations.find((location) => { // this returns the matched location
         
         return location.id === loc;
          
        });
      },
    },