I was hoping to resolve this on my own, but I am completely stuck. Any help is welcomed. Basically, this component prints a matrix 100×10 such as this:
Threat1: AssetType1 AssetType2 AssetType3 AssetType4 […]
Threat2: AssetType1 AssetType2 AssetType3 AssetType4 […]
Threat3: AssetType1 AssetType2 AssetType3 AssetType4 […]
Threat4: AssetType1 AssetType2 AssetType3 AssetType4 […]
[…]
Basically, each threat is related to different types of assets. Both threats and Asset types are dynamc and are retrieved from a GraphQL backend.
Each row is a v-chip-group that controls the v-chips (Asset types) on that row, and the whole matrix is dinamically formed with a couple of v-fors:
<v-row v-for="(threat, index) in threats" :key="threat.short"> <v-col> <v-card"> {{threat.id}}.- {{threat.name}} </v-card> </v-col> <v-col> <v-chip-group :value="associations[index]" multiple > <v-chip v-for="(type, index2) in assettypes" :key="type.id" @click="getClick(index, index2)" > </v-chip> </v-chip-group> </v-col> </v-row> [...] // This function gets the row and the column clicked getClick(row, column){ //this.$refs.$emit("input") var position = this.associations[row].indexOf(column) if (position > -1){ this.associations[row][position] = -1 } else { this.associations[row][this.associations[row].length] = column } },
I am running into several problems with this thing. The matrix is not really huge, but big enough to not wanting to render it very often (and I will need to do something very similar with a bigger one, maybe 150 x 100). The contents are stored in a multidimensional array named “associations”, that is initialized at the beginning with push().
The first thing I found is that with v-model, all v-chips were rendered with any click on a v-chip. I can’t get unique v-chip keys and I thought that might be the reason. So I moved to v-bind and a custom event handler for @click.
Then, I found that using splice() and push() was causing the same re-rendering, so I reverted to direct assignations (array[] = something), and I reduced the re-rendering to only the v-chip that was being clicked.
I am aware that I am probably complicating things too much, but in any case, that seems solved for now and I can’t think of a better solution right now.
The thing now is that the very first click on each row seems to “get lost”. In short, the V-chip does not emit the input() event, and the v-chip does not update, but only with the very first click. After that first click, the next clicks on the same row work perfectly. I’ve also found that this very first click re-renders all the elements on the table. I can’t see why, sincerely.
Then I found a funny thing. Just trying to make it work, I added the “this.$refs.$emit(“input”)” line at the beginning of the click handler. The one that is commented. I got a Vue warning “Error in v-on handler: “TypeError: this.$refs.$emit is not a function”, what seems logical… but it worked: the input event was being emitted by v-chip and the page was not rendering with the first click. But I don’t understand why, as it makes no sense at all (to me).
I suspect the initial re-rendering and the input event not emitting are related, but I can’t find the source of the problem. Any ideas, suggestions are welcomed.
Advertisement
Answer
Couple of thoughts:
This might be one of those issues related to your :key
not being unique.
Instead of :key="threat.short"
try :key="`threat-short-${index}`"
Check your console logs if there are any duplicate key warnings.
Also, it might be due to :value="associations[index]"
and the way Vue reactivity for Arrays works.
I suspect Vue not reacting to the first click due to using an array like this.
You could wrap it in a function:
getRow(index){ return this.associations[index]; }
Or as a test, try to create a computed property for just 1 row and see if that fixes it. If it does than this might be your problem.
Could you maybe make an online demo showcasing the bug? Then I could maybe fix it.