v-if inside v-for showing last element in array - vue.js

I'm new to Vue and having a hard time nesting a v-if inside a v-for. Everything renders but {{row.id}} (inside my v-if) is showing the last element in my array instead of the selected one. The function work fine as I pass row as an argument. I'm assuming I have to do something similar here but I can't find an example or explanation in the docs.
Is there a way to pass the entire array to my modal template or do I have to structure this differently?
<tr v-for="row in rows">
<td><img v-bind:src="row.image" height="180" width="130"></td>
<td>{{row.title}}</td>
<td>{{row.platform}}</td>
<td>
<button id="edit"><img v-on:click="onClickEdit(row)" #click="showModal = true" src='images/edit.png' height='30' width='30'></button>
<modal v-if="showModal" #close="showModal = false">
<h3 slot="header">{{row.id}}</h3>
</modal>
</td>
</tr>
Any help is appreciated :)

The problem is that each row has a modal. It's not that the modal is showing the last element only, it's that when showModal is true, all modals is displayed, the last modal is on top and the other modals are below it.
quickest way to make this work is to set showModal to the row.id
#click="showModal = row.id"
and for the modal, use row.id for the v-if
<modal v-if="showModal === row.id" #close="showModal = false">

Related

vuetify data table passing an item from parent to child to colour a field

Learning Vuetify and Vuetify (Loving both) but come across an issue I can't figure out so would appreciate someone sharing best practice please
I have created a component that contains a vuetify datatable and I pass the titles and items via props from a parent to the child, so far so good
The bit I can't figure out is that I want to loop through a specific field (the example I am using is item.calories as per the docs) and run a function over it.
I assume I pass the item.calories field as a prop but how do I then send that to a function
in my parent I pass to my DataTable component as follows
<DataTable
:headers="headers"
:content="content"
title="This is my data table title"
:myCalories="content.calories" <-- This bit is causing me the issue
/>
How in my DataTable component can I change the below to use the :myCalories prop, or is there a better approach I could consider?
<template v-slot:[`item.calories`]="{ item }">
<v-chip
:color="getColor(item.calories)"
dark
>
{{ item.calories }}
</v-chip>
</template>
My function
methods: {
getColor (calories) {
if (calories > 400) return 'red'
else if (calories > 200) return 'orange'
else return 'green'
},
},
I did wonder if I should run the function in the parent first and pass the result over but if you could advise on the best practice way to achieve the above it would be very much appreciated
Gibbo
I'm not sure it this will help but I had a similar problem and ended up using the body slot of the v-data-table and redefined my whole table.
This workaround could help you but this is certainly not the best approach to do it
<template v-slot:body="{ items, headers }">
<tbody>
<tr v-for="item in items" :key="item.name">
<td v-for="column in headers" :key="column.value">
<div v-if="column.value === 'calories'" :style="getColor(item.calories)">
{{ item[column.value] }}
</div>
<div v-else>
{{ item[column.value] }}
</div>
</td>
</tr>
</tbody>
</template>
Here is the codepen example https://codepen.io/taghurei-the-reactor/pen/YzaBNxw?editors=1111

Vue Components Losing Image When Rerendered

I have a sidebar component located in a view-router view component that renders several child component buttons. It renders the child components using v-for loops.
<div v-for="type in this.facebookLightButtons" :key="type">
<SidebarButton :type="type"/>
</div>
<div v-for="type in this.facebookButtons" :key="type">
<SidebarButton :type="type"/>
</div>
facebookLightButtons is simply an array of strings containing the text of the button (which is also the name of the image source of the button). The result is the following:
The corresponding code in the SidebarButton components are:
<template>
<div>
<router-link :to="'/' + capitalizeFirstLetter(type)" class="sidebar-button">
<table>
<tr>
<td>
<img class="sidebar-button-icon" :src="getImage" />
</td>
<td>
<p>{{capitalizeFirstLetter(type)}}</p>
</td>
</tr>
</table>
</router-link>
</div>
</template>
and
computed: {
getImage() {
return require('#/assets/images/SidebarIcons/' + this.type + '.png');
}
}
When I change to a new view-router view and then return to the home page where this sidebar is located, the images are all missing:
I am trying to figure out how to keep the images there when returning to the home page.
Things I have tried:
Clearing and setting the image source in the SidebarButton components in the created, beforeMount, mounted, activated, deactivated, updated, and unmounted lifecycle hooks (non of which seemed to work).
Clearing the image, waiting for 2000 milliseconds using setTimeout() and then setting the image to the correct image source
Wrapping both the contents of the SidebarButton template as well as the v-for loop in the parent component with a <keep-alive> tag
Hard coding each SidebarButton component instead of using a v-for loop
It seems like something must be missing. What can I do to ensure that these images stored locally on my computer not only show when first displayed, but also appear when the user returns to the homepage after entering a separate view-router view?

Style Binding not updating with template structure [Vue]

In my example I want to draw a border around an element after clicking on it. In this example it works perfectly:
<div v-for="(parent, index) in $store.getters.getInfo" :key="index">
<div #click="setClicked" :id="child.id" v-for="child in parent"
:style="[child.clicked ? {'border-color': 'black'} : {'border-color': 'white'}]">
</div>
</div>
But when i try with a bit more complicated structure and template tags the style binding fails to be triggered:
<div v-for="i in 12">
<template v-for="(user, index) in $store.getters.getSharedUsers">
<div :id="child.id" v-for="child in $store.getters.getSharedInfo[user[0]][i-1]"
:userID="child.userID" #click="setClicked"
:style="[child.clicked ? {'border-color': 'black'} : {'border-color': 'white'}]">
</div>
</template>
</div>
In my mutation I set the attribute with:
Vue.set(state.element_map[payload.uID][payload.dID], 'clicked', true);
When I debug I see the change in both code examples in my data structure after calling the setClicked function, but only in the first one the style binding is triggered and the border is drawn. The only difference I see is the use of the template tag and the more complicated data structure. But it should also work in the second example as the clicked attribute is set correctly. So what am I missing? Thanks!

vue dom doesn't re-render

I use v-for to render table rows
<table>
<tr v-for="(item, i) in data">
<td>
<button v-if="...">....</button>
<el-tooltipplacement="right">
<button v-if="..." >...</button>
<div slot="content">
<button #click="...">...</button>
<button #click="...">...</button>
</div>
</el-tooltip>
</td>
</tr>
</table>
The tooltip is a component of element ui,
the tooltip will display after hovering the button.
The table data is gotten by ajax call,
and there are several pages,
it will get the data by ajax call while turning page,
the problem occurs after turning page.
Some tooltip will not display after hovering,
I assumed the problem is doms don't re-render,
I used $forceUpdate() after ajax call,
but it had no effect.
If you can please help me out.
element ui Tooltip component and exmaple: https://element.eleme.io/#/en-US/component/tooltip

How to change the content of the standard-modal?

I am a Vue.js beginner... Supposing that the simplest and "standard" modal for Vue is https://v2.vuejs.org/v2/examples/modal.html
But there are no ID or setter methodod to change the modal-body. I have many buttons and each one will show a different contengt (innerHTML) in the modal.. .But need only one Vue's modal object (not make sense do many if only changes title and content)... The content is not static is a string or inner HTML form other DOM object.
EDIT: as I discussing bellow, the key of the problem/solution and the question perhaps is "how to set a slot?"
The best is to see also this question/answer about set string into innerHTML of the slot.
<div id="app">
<button #click="showModal=true">Show Modal1</button>
<button #click="showModal=true">Show Modal2</button>
<modal v-if="showModal" #close="showModal = false">
<!-- HOW TO CHANGE HERE?? DYNAMICALLY, ON FLY,
WITH PURE JAVASCRIPT
WHEN click buttoom "Show Modal1" say "HELLO!"
WHEN click buttoom "Show Modal2" say "BYE!"
... or get content from a web-service
-->
<h3 slot="header">custom header</h3>
</modal>
</div>
They are all slots, so you can parameterized them.
E.g. in parent:
<modal v-if="showModal" #close="showModal = false">
<h3 slot="header">custom header</h3>
<p slot="body">custom body</p>
<p slot="footer">
<button class="modal-default-button" #click="showModal = false">
OK
</button>
</p>
</modal>
This would change all three parts (header, body and footer).
Updated JSFiddle here.
Creating multiple modals
To create multiple, you can have as many <modal>s as wanted, provided you create a "show" variable for each one (e.g. showModal):
<button id="show-modal" #click="showModalOne = true">Show Modal One</button>
<button id="show-modal" #click="showModalTwo = true">Show Modal Two</button>
<modal v-if="showModalOne" #close="showModalOne = false">
...
</modal>
<modal v-if="showModalTwo" #close="showModalTwo = false">
...
</modal>
And the data:
new Vue({
el: '#app',
data: {
showModalOne: false,
showModalTwo: false,
}
})
Two modal JSFiddle here.