Christopher Nelson
Christopher Nelson

Reputation: 1017

Assign local variable during a v-for loop in Vue JS

I'm struggling coming up with a solution to what seems to be a basic problem.

I have a template that uses a v-for loop to create some content, inside this content I need to run a function to check to see if the contentID matches an ID from a separate list. If it matches I need to take that data and show it in my loop . Currently the only way to get that data is to run the function that checks multiple times, i.e

methods: {
findClientName (clientId) {
  for (let name of this.clientList) {
    if (name.id == clientId) {
      return {
        name
      }
    }
  }
}

<v-card-text>
    {{ findClientName(item.client_id).name.f_name }}
    {{ findClientName(item.client_id).name.l_name }}
</v-card-text>

That seems like a pretty ineffective way of doing it because I need to call the method on every part of the data I want, isn't there a way to just assign it to a local variable inside the template, like..

{ clientData = findClientName(item.client_id) }
{{ clientData.f_name }}
{{ clientData.l_name }}

What am I missing or not thinking of?

Upvotes: 6

Views: 8002

Answers (4)

Luca C.
Luca C.

Reputation: 12564

This is the best workaround I found for this lacking of local variables, that is by wrapping the value as mono-element array, since VUE natively supports array iteration:

<template v-for="local_variable in [object.longComputationValueProducer().evenMoreCPUWork()]">
    <!-- body guaranteed to be executed exactly 1-->
    <div>{{ local_variable.read }}</div>
    <div>{{ local_variable.read_without_recompute }}</div>
    <div>{{ local_variable.read_again_without_recompute }}</div>
</template>

Upvotes: 1

Adem yal&#231;ın
Adem yal&#231;ın

Reputation: 206

I think computed is better than method because it is depend your localId

computed: {
   getClientsById (clientId) {
     return this.currentClientList.filter((ccl) => { return this.currentClientList.id === localId });
   }
} 


<v-card-text v-for="item in getClientById">
    {{ item.name }}
</v-card-text>


// Second way without methods and computed

<v-card-text v-for="item in currentClientList" v-if=item.id === localId>
    {{ item.name }}
</v-card-text>

Upvotes: 0

Brian Lee
Brian Lee

Reputation: 18187

You're going to have to do some sort of lookup if the data you need is in another list. Is it possible to normalize the client list before hand and use that in the template loop? Something along the lines of:

data () {
  return {
    mapped: [],
    clientList: [...]
  }
},
mounted () {
  this.mapped = this.clientList.map(({ id, f_name, l_name }) => {
    return { [id]: { f_name, l_name } }
  })
}

Then your template would be:

<template>
 ...
    <v-card-text v-if="mapped.hasOwnProperty(item.client_id)">
      {{ mapped[item.client_id].f_name }}
      {{ mapped[item.client_id].l_name }}
    </v-card-text>
 ...
</template>

Upvotes: 1

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

It's recommended to use a computed property in this case, and loop through that property via v-for, i provided an example to simulate your case :

new Vue({
  el: '#app',
  data: {
    a: ["aaa", "bbb", "ccc", "ddd", "eee", "fff"],
    b: ["bbb", "sss", "ccc", "eee"]
  },
  computed: {
    isInA() {
      return this.b.filter((item) => {
        return this.a.includes(item)
      })
    }
  }

})
<!DOCTYPE html>
<html>

<head>
  <meta name="description" content="Vue.delete">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.min.js"></script>
</head>

<body>
  <div id="app">
    <div v-for="item in isInA">
      {{item}}
    </div>
  </div>

If your arrays contain objects like in your case, you need something like :

computed:
 cpt_clients(){
return this.clientList.filter((cl)=>{
                          return this.otherList.findIndex(item=>{return item.id==cl.id;})!==-1;
                        });
         }
       }

and in your template do :

  <v-card-text v-for="cl in cpt_clients" >
       {{cl.name}}
        {{cl.id}}
   </v-card-text>

Upvotes: 3

Related Questions