Prevent v-navigation-drawer from closing - javascript

Expected Behavior: 1. On initial render, the component should auto open the corresponding v-list-item's subgroup. 2. Then, on clicking an adjacent subgroup item, the nav drawer should remain opened to the subgroup the user has click on.
Problem: When performing 2, the entire nav drawer will close rather than the expected behavior.
I still need to keep the :value v-binds, but I believe the problem has something to do with preventing the #activator from propagating v-on when clicking an item.
Oddity: Any subsequent clicks on nav drawer items will result in normal behavior after experiencing the initial problem.
Any help would be appreciated if you've come across this problem before. Thank you!
<template>
<div>
<v-app>
<v-list>
<v-list-group
v-for="(subObjects, fruit) in items"
:key="fruit"
:value="fruit === 'orange'"
no-action
>
<template #activator>
<v-list-item-title>
{{ fruit }}
</v-list-item-title>
</template>
<template>
<v-list-group
v-for="object in subObjects"
:key="object.name"
:value="object.name === 'navel'"
no-action
sub-group
>
<template #activator>
<v-list-item-content>
<v-list-item-title>
{{ object.name }}
</v-list-item-title>
</v-list-item-content>
</template>
<v-list-item
v-for="year in object.dates"
:key="year"
>
<template #activator="{ on, attrs }">
<v-list-item-title v-bind="attrs" v-on="on">
{{ year }}
</v-list-item-title>
</template>
</v-list-item>
</v-list-group>
</template>
</v-list-group>
</v-list>
</v-app>
</div>
</template>
<script>
export default {
data() {
return {
items: {
apples: {
0: {
color: 'red',
name: 'fuji',
dates: ['2016', '2018'],
},
1: {
color: 'green',
name: 'granny smith',
dates: ['2020', '2021'],
}
},
oranges: {
0: {
color: 'orange',
name: 'navel',
dates: ['2022']
},
1: {
color: 'red orange',
name: 'blood orange',
dates: ['2015', '2017'],
}
},
}
};
},
};
</script>

Related

Expand the image by clicking on it (vuetify)

I am continuing to use vuetify for my small personal project to study vue and vuetify well, i am using v-col and v-img to create a gallery of images and i would like to click on each image to go to full screen (in style lightbox) but it seems that vuetify doesn't have this native capability, is it possible? it seems strange that there is not. Can anyone suggest me a solution? Sorry maybe the silly question but as said i'm a beginner
I am attaching the code
<template>
<div class="gallery">
<h1 class="subtitle-1 grey--text pa-2 d-flex justify-center">Galleria</h1>
<v-divider></v-divider>
<v-container class="my-5">
<div>
<v-row>
<v-col v-for="item in items" :key="item.id" class="d-flex child-flex" cols="4" >
<v-img :src="item.src" contain class="grey lighten-2">
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
</v-row>
</div>
</v-container>
</div>
</template>
<script>
// # is an alias to /src
export default {
name: 'Gallery',
data(){
return {
items: [
{id: 1, src: require("../assets/images/img1.jpg")},
{id: 2, src: require("../assets/images/img2.jpg")},
{id: 3, src: require("../assets/images/img3.jpg")},
{id: 4, src: require("../assets/images/img4.jpg")},
{id: 5, src: require("../assets/images/img5.jpg")},
{id: 6, src: require("../assets/images/img6.jpg")},
{id: 7, src: require("../assets/images/img7.jpg")},
{id: 8, src: require("../assets/images/img8.jpg")},
]
}
}
}
</script>
I thing v-overlay component is exactly what you need. Just put v-img or simple img with correct src attribute inside of it.
You could toggle the fullscreen onClick #click="toggleFullscreen(element)" on your img, but you would need to provide the Element e.g. by Ref or Id. An example toggle method:
toggleFullscreen(element) {
if (document.fullscreenElement) {
return document.exitFullscreen() // exit fullscreen on next click
}
if (element.requestFullscreen) {
element.requestFullscreen()
} else if (this.element.webkitRequestFullscreen) {
element.webkitRequestFullscreen() // Safari
} else if (this.element.msRequestFullscreen) {
element.msRequestFullscreen() // IE11
}
}
References: https://www.w3schools.com/jsref/met_element_requestfullscreen.asp, https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen

Vue.js Getting erros even if component is not rendered

I have a component that only renders if there is data to show.
<v-row v-if="openPositions.length !== 0" justify="center" align="end" class="mt-1">
This works perfectly.
However, even when this component is not rendered, error messages are printed, because some data is undefined within this component, but that's why I'm not displaying the table in the first place.
How can I stop these error messages?
===== EDIT =====
Below you can see the complete component code and below that the error from the console.
<template>
<v-row v-if="openPositions.length" justify="center" align="end" class="mt-1">
<v-col sm="12">
<v-data-table
v-if="this.full"
dense
align="center"
:headers="headers_full"
:items="openPositions"
hide-default-footer
>
<template v-slot:item.symbol="{ item }">
<span>{{ item.symbol }}</span>
</template>
<template v-slot:item.size="{ item }">
<span v-if="item.side === 'sell'" class="error--text">{{
item.size
}}</span>
<span v-if="item.side === 'buy'" class="success--text">{{
item.size
}}</span>
</template>
<template v-slot:item.position_value="{ item }">
<span>
{{ item.position_value.toFixed(6) }}
</span>
</template>
<template v-slot:item.entry_price="{ item }">
<span>
{{ item.entry_price.toFixed(2) }}
</span>
</template>
<template v-slot:item.liq_price="{ item }">
<span>
{{ item.liq_price.toFixed(2) }}
</span>
</template>
<template v-slot:item.position_margin="{ item }">
<span>
{{ item.position_margin.toFixed(6) }}
</span>
</template>
<template v-slot:item.unrealised_pnl_last="{ item }">
<span v-if="item.unrealised_pnl_last < 0" class="error--text">
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
<span v-else-if="item.unrealised_pnl_last > 0" class="success--text">
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
<span v-else>
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
</template>
<template v-slot:item.realised_pnl="{ item }">
<span v-if="item.realised_pnl < 0" class="error--text">
{{ item.realised_pnl.toFixed(6) }}
</span>
<span v-else-if="item.realised_pnl > 0" class="success--text">
{{ item.realised_pnl.toFixed(6) }}
</span>
<span v-else>
{{ item.realised_pnl.toFixed(6) }}
</span>
</template>
<template v-slot:item.daily_total="{ item }">
<span v-if="item.daily_total < 0" class="error--text">
{{ item.daily_total.toFixed(6) }}
</span>
<span v-else-if="item.daily_total > 0" class="success--text">
{{ item.daily_total.toFixed(6) }}
</span>
<span v-else>
{{ item.daily_total.toFixed(6) }}
</span>
</template>
<template v-slot:item.market_close="{ item }">
<v-btn x-small color="primary" #click="marketClose(item)">
Close
</v-btn>
</template>
</v-data-table>
<v-data-table
v-else
dense
align="center"
:headers="headers_reduced"
:items="openPositions"
hide-default-footer
>
<template v-slot:item.symbol="{ item }">
<span>{{ item.symbol }}</span>
</template>
<template v-slot:item.size="{ item }">
<span v-if="item.side === 'sell'" class="error--text">{{
item.size
}}</span>
<span v-if="item.side === 'buy'" class="success--text">{{
item.size
}}</span>
</template>
<template v-slot:item.position_value="{ item }">
<span>
{{ item.position_value.toFixed(6) }}
</span>
</template>
<template v-slot:item.entry_price="{ item }">
<span>
{{ item.entry_price.toFixed(2) }}
</span>
</template>
<template v-slot:item.liq_price="{ item }">
<span>
{{ item.liq_price.toFixed(2) }}
</span>
</template>
<template v-slot:item.position_margin="{ item }">
<span>
{{ item.position_margin.toFixed(6) }}
</span>
</template>
<template v-slot:item.unrealised_pnl_last="{ item }">
<span v-if="item.unrealised_pnl_last < 0" class="error--text">
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
<span v-else-if="item.unrealised_pnl_last > 0" class="success--text">
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
<span v-else>
{{ item.unrealised_pnl_last.toFixed(6) }}
</span>
</template>
<template v-slot:item.realised_pnl="{ item }">
<span v-if="item.realised_pnl < 0" class="error--text">
{{ item.realised_pnl.toFixed(6) }}
</span>
<span v-else-if="item.realised_pnl > 0" class="success--text">
{{ item.realised_pnl.toFixed(6) }}
</span>
<span v-else>
{{ item.realised_pnl.toFixed(6) }}
</span>
</template>
<template v-slot:item.daily_total="{ item }">
<span v-if="item.daily_total < 0" class="error--text">
{{ item.daily_total.toFixed(6) }}
</span>
<span v-else-if="item.daily_total > 0" class="success--text">
{{ item.daily_total.toFixed(6) }}
</span>
<span v-else>
{{ item.daily_total.toFixed(6) }}
</span>
</template>
<template v-slot:item.market_close="{ item }">
<v-btn x-small color="primary" #click="marketClose(item)">
Close
</v-btn>
</template>
</v-data-table>
</v-col>
</v-row>
</template>
<script>
import store from "../store";
export default {
store,
name: "OpenPositions",
components: {},
props: [],
data() {
return {
dialog: false,
headers_full: [
{ text: "Open Position", value: "symbol" },
{ text: "Qty", value: "size" },
{ text: "Value", value: "position_value" },
{ text: "Price", value: "entry_price" },
{ text: "Liq. Price", value: "liq_price" },
{ text: "Margin", value: "position_margin" },
{ text: "Leverage", value: "leverage" },
{
text: "Unrealized P&L",
value: "unrealised_pnl_last",
},
{ text: "Daily Realized P&L", value: "realised_pnl" },
{ text: "Daily Total (% of Account)", value: "daily_total" },
{ text: "SL", value: "stop_loss" },
{ text: "TP", value: "take_profit" },
{ text: "TS", value: "trailing_stop" },
{ text: "Stops", value: "trading_stops" },
{ text: "Market close", value: "market_close" },
],
headers_reduced: [
{ text: "Open Position", value: "symbol" },
{ text: "Qty", value: "size" },
{ text: "Value", value: "position_value" },
{ text: "Price", value: "entry_price" },
{ text: "Liq. Price", value: "liq_price" },
{ text: "Margin", value: "position_margin" },
{ text: "Leverage", value: "leverage" },
{
text: "Unrealized P&L",
value: "unrealised_pnl_last",
},
{ text: "Daily Realized P&L", value: "realised_pnl" },
{ text: "Daily Total (% of Account)", value: "daily_total" },
{ text: "Market close", value: "market_close" },
],
};
},
methods: {
async marketClose(item) {
await this.$apiAbstraction.marketOrder(
item.symbol,
item.side === "buy" ? "sell" : "buy",
Math.abs(item.size)
);
},
},
computed: {
openPositions() {
return store.getters.getOpenPositionsByExchange(
store.getters.getExchange
);
},
full() {
return store.getters.getExchange !== "deribit";
},
},
mounted() {},
};
</script>
<style scoped></style>
The error:
[Vue warn]: Error in render: "TypeError: item.position_value.toFixed is not a function"
found in
---> <VData>
<VDataTable>
<OpenPositions> at src/components/OpenPositions.vue
<Ladder> at src/views/Ladder.vue
<VMain>
<VApp>
<App> at src/App.vue
<Root>
warn # vue.runtime.esm.js?2b0e:619
logError # vue.runtime.esm.js?2b0e:1884
globalHandleError # vue.runtime.esm.js?2b0e:1879
handleError # vue.runtime.esm.js?2b0e:1839
Vue._render # vue.runtime.esm.js?2b0e:3550
updateComponent # vue.runtime.esm.js?2b0e:4066
get # vue.runtime.esm.js?2b0e:4479
run # vue.runtime.esm.js?2b0e:4554
flushSchedulerQueue # vue.runtime.esm.js?2b0e:4310
eval # vue.runtime.esm.js?2b0e:1980
flushCallbacks # vue.runtime.esm.js?2b0e:1906
Promise.then (async)
timerFunc # vue.runtime.esm.js?2b0e:1933
nextTick # vue.runtime.esm.js?2b0e:1990
queueWatcher # vue.runtime.esm.js?2b0e:4402
update # vue.runtime.esm.js?2b0e:4544
notify # vue.runtime.esm.js?2b0e:730
reactiveSetter # vue.runtime.esm.js?2b0e:1055
setOpenPositions # exchanges.js?d86e:169
wrappedMutationHandler # vuex.esm.js?2f62:840
commitIterator # vuex.esm.js?2f62:462
eval # vuex.esm.js?2f62:461
_withCommit # vuex.esm.js?2f62:620
commit # vuex.esm.js?2f62:460
boundCommit # vuex.esm.js?2f62:405
handleOnMessage # deribitApi.js?89c3:141
_this.ws.onmessage # deribitApi.js?89c3:59
ReconnectingWebSocket._handleMessage # reconnecting-websocket-mjs.js?d096:172
vue.runtime.esm.js?2b0e:1888 TypeError: item.position_value.toFixed is not a function
at fn (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"7c63af54-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/OpenPositions.vue?vue&type=template&id=3ad75d40&scoped=true& (app.js:1010), <anonymous>:279:64)
at normalized (vue.runtime.esm.js?2b0e:2590)
at eval (Row.ts?6e51:31)
at Array.map (<anonymous>)
at render (Row.ts?6e51:22)
at createFunctionalComponent (vue.runtime.esm.js?2b0e:3058)
at createComponent (vue.runtime.esm.js?2b0e:3231)
at _createElement (vue.runtime.esm.js?2b0e:3434)
at createElement (vue.runtime.esm.js?2b0e:3353)
at VueComponent.vm.$createElement (vue.runtime.esm.js?2b0e:3494)
Edit (after seeing the actual error):
The problem is you're trying to use .toFixed on something that is not a number. To guard against it, you have to wrap the value in Number.
Number(item.daily_total || 0).toFixed(6)
Also, your item.daily-total template slot can be significantly simplified as:
<template v-slot:item.daily_total="{ value }">
<span :class="{ 'error--text': value < 0, 'success--text': value > 0 }"
v-text="Number(value || 0).toFixed(6)" />
</template>
Obviously, you should use a similar approach to the other templates as well.
Because you use it in more than one place, you could DRY your code up and use a Vue component to apply the success/error classes:
<template>
<span :class="cellClass"
v-text="Number(value || 0).toFixed(toFixed || 2)" />
</template>
<script>
export default Vue.extend({
name: 'CellValue',
props: ['value', 'item', 'header', 'toFixed'],
computed: {
cellClass() {
return {
'error--text': this.value < 0,
'success--text': this.value > 0
}
}
}
})
</script>
...import it as a Vue component and use it in your table templates as:
<template v-slot:item.daily_total="cell">
<cell-value v-bind="cell" :to-fixed="6" />
</template>
You don't need to declare item or header as props, but they're provided by the Vuetify slot, in case you need them.
Note I also added an extra prop called to-fixed, defaulting to 2 which determines the number of decimals. You could rename it decimals.
Also note I default the value to 0 to avoid any errors around using .toFixed() on anything that's not of type number.
If, for example, you prefer to display a custom text when the value is of any other type than number, you could use something more elaborate in CellValue's template:
<template>
<span :class="cellClass">
<template v-if="typeof value === 'number'">
{{ value.toFixed(toFixed || 2) }}
</template>
<template v-else>
<code>{{ value || '--' }}</code>
</template>
</span>
</template>
For reference, I'm leaving here the initial answer, as it might help others:
Whenever your template depends on an expression which errors in some cases because it tries to access properties/methods of undefined entities, the easiest workaround is to create a computed property which avoids the exception:
<template>:
<v-row v-if="hasOpenPositions" justify="center" align="end" class="mt-1">
<script>:
computed: {
hasOpenPositions() {
return this.openPositions && this.openPositions.length !== 0;
}
}
However, be warned the above computed will return true when openPositions is truthy and it doesn't have a length property (when its length is undefined; i.e.: openPositions: {} - because undefined !== 0).
Another slightly shorter syntax I find myself using is:
computed: {
hasOpenPositions() {
return !!(this.openPositions?.length);
}
}
(This one only returns true when openPositions has a truthy length, which is probably what you want).
Do note optional chaining (?.) does not work in <template>, at least for now.
The above is a general workaround which comes in handy with deep objects, so your template doesn't error when the objects have not yet been populated/loaded.
However, if openPositions is an array, you should just instantiate it as an empty array and simplify your check as:
<template>:
<v-row v-if="openPositions.length" justify="center" align="end" class="mt-1">
<script>:
data: () => ({
openPositions: []
}),
mounted() {
this.$http.get('some/api').then(r => { this.openPositions = r.data })
}
The relevant bit here is openPositions is an array at all times (so it always has a length internal method) and that it's reactive. How you update it (in mounted or some method) is irrelevant.

How to use object as a tag while using the Form Tags component in bootstrap vue

To explain the question, using the code from documentation as below:
<template>
<div>
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, inputAttrs, inputHandlers, addTag, removeTag }">
<b-input-group aria-controls="my-custom-tags-list">
<input
v-bind="inputAttrs"
v-on="inputHandlers"
placeholder="New tag - Press enter to add"
class="form-control">
<b-input-group-append>
<b-button #click="addTag()" variant="primary">Add</b-button>
</b-input-group-append>
</b-input-group>
<ul
id="my-custom-tags-list"
class="list-unstyled d-inline-flex flex-wrap mb-0"
aria-live="polite"
aria-atomic="false"
aria-relevant="additions removals"
>
<!-- Always use the tag value as the :key, not the index! -->
<!-- Otherwise screen readers will not read the tag
additions and removals correctly -->
<b-card
v-for="tag in tags"
:key="tag"
:id="`my-custom-tags-tag_${tag.replace(/\s/g, '_')}_`"
tag="li"
class="mt-1 mr-1"
body-class="py-1 pr-2 text-nowrap"
>
<strong>{{ tag }}</strong>
<b-button
#click="removeTag(tag)"
variant="link"
size="sm"
:aria-controls="`my-custom-tags-tag_${tag.replace(/\s/g, '_')}_`"
>remove</b-button>
</b-card>
</ul>
</template>
</b-form-tags>
</div>
</template>
<script>
export default {
data() {
return {
value: ['apple', 'orange', 'banana', 'pear', 'peach']
}
}
}
</script>
The above code gives the output as follows:
But when I have the values as an array of objects instead of short strings how to render the properties of the objects as tag elements?
for example: If I have value: [{name: 'apple', color: 'red'}, {name:'mango', color: 'yellow'}] then how to get the same output as above?
I tried something something like <strong>{{ tag.name }}</strong> and it doesn't work and gives me only empty tags to remove as follows:
Any ideas on how to achieve what I wanted to do here?
What you're trying to do is not support yet according to this issue
You'll have to map your array of objects to a string array and utilize that.
Then once you're ready to "use" your tags, you could map them back based on the original objects.
Here's a rather simple example of what could be done.
new Vue({
el: "#app",
computed: {
mappedTags() {
/* This is case sensitive */
return this.options.filter(option => this.value.includes(option.name))
}
},
data: {
value: [],
options: [{
name: 'Mango',
color: 'Orange'
},
{
name: 'Orange',
color: 'Orange'
},
{
name: 'Lemon',
color: 'Yellow'
},
{
name: 'Apple',
color: 'Red'
},
{
name: 'Banana',
color: 'Yellow'
},
]
}
})
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.4.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.js"></script>
<style>
/* Only added for better visibility on the text */
.text-stroke {
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
</style>
<div id="app" class="p-3">
Valid (<b>Casesensitive</b>) tags - [Banana, Apple, Orange, Mango]
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, inputAttrs, inputHandlers, addTag, removeTag }">
<b-input-group aria-controls="my-custom-tags-list">
<b-input
v-bind="inputAttrs"
v-on="inputHandlers"
placeholder="New tag - Press enter to add"></b-input>
<b-input-group-append>
<b-button #click="addTag()" variant="primary">Add</b-button>
</b-input-group-append>
</b-input-group>
<ul class="list-unstyled d-inline-flex flex-wrap mb-0">
<b-card
v-for="tag in mappedTags"
:key="tag.name"
:id="`my-custom-tags-tag_${tag.name.replace(/\s/g, '_')}_`"
tag="li"
class="mt-1 mr-1"
body-class="py-1 pr-2 text-nowrap"
>
<strong :style="`color: ${tag.color}`" class="text-stroke">
{{ tag.name }}
</strong>
<b-button
#click="removeTag(tag.name)"
variant="link"
>
Remove
</b-button>
</b-card>
</ul>
</template>
</b-form-tags>
{{ mappedTags }}
</div>
Replace {{ tag.name }} with {{ JSON.parse(tag).name }}.
That should solve the problem.
You have a similar example where I needed the input of the user and its selection and gather does two inputs values inside an array of objects.
You need to add a v-model to your inputs this way you can pass it to a custom function
<b-form-input
v-model="werkTagNombre"
<b-form-select
v-model="werkTagExp"
...
"#click="addingWerkTag({werkTagNombre, werkTagExp})"
Complete template code
<b-form-tags v-model="freelance.tags.nombre">
<template v-slot="{ inputAttrs, inputHandlers }">
<b-input-group aria-controls="tags-list">
<b-form-input
v-model="werkTagNombre"
v-bind="inputAttrs"
v-on="inputHandlers"
placeholder="Seleccione"
class="werk-input werk-shadow-input mr-2"
>
</b-form-input>
<b-input-group-append>
<b-form-select
v-model="werkTagExp"
:options="experienciaOptions"
class="werk-input werk-shadow-input ml-2 mr-2"
>
</b-form-select>
</b-input-group-append>
<b-input-group-append>
<b-button class="shadow-none ml-2" style="border-radius:6px;"#click="addingWerkTag({werkTagNombre, werkTagExp})"> ADD</b-button>
</b-input-group-append>
</b-input-group>
<span style="font-size: 10px; color: #a5a5a5;">TAGS:</span>
<ul id="tags-list" class="list-unstyled d-inline-flex flex-wrap mb-0 mt-1">
<b-badge
v-for="(werkTag, index) in freelance.tags"
:key="index"
tag="li"
class="mx-1 my-1 werk-tags"
>
{{werkTag.nombre}} {{werkTag.experiencia}}
</b-badge>
</ul>
</template>
</b-form-tags>
Script
export default {
data() {
return {
freelance: {
tags: [
{
nombre:" Test name",
experiencia:1
}
],
}
...
werkTagNombre: '',
werkTagExp: '0',
experienciaOptions: [
{ value: '0', text: 'Selecciona'},
{ value: 1, text: 'menor a 2 años'},
{ value: 2, text: '3 a 5 años'},
{ value: 3, text: 'mayor a 5 años'},
]
...
methods:{
addingWerkTag(valor){
this.freelance.tags.push({nombre: valor.werkTagNombre, exp: valor.werkTagExp});
},
...
}
If you want you can also pass the addTag default function like this:
Inside the template slot add the functions like "addtag"
<template v-slot="{ inputAttrs, inputHandlers, addTag }">
...
So you can add it to your custom function like this:
#click="addingWerkTag({ werkTagNombre, werkTagExp, addTag })"

How to append a font-awesome icon to a newly created element within vueJS / Vuetify?

I am trying to create a user list in which the user selects their icon from a row of icons. They activate a modal, enter their information, and select 'add user'. I am having trouble getting the value of the icon clicked, as you can see below I use this.icons[0] which will console log. But I cannot successfully get them to dynamically log. In addition I cannot successfully add the icon to the person (even in the case of calling the index, as stated above. What would be the best/cleanest way to do this? I cleaned out the code a bunch, but this should give a solid understanding of such. If I can provide any further code or info, let me know. Thanks in advance!
<template>
<div>
<v-expansion-panel v-for="user in users" :key="user.name" class="mb-1">
<v-expansion-panel-content>
<div slot="header" class="flex-row">
<v-icon>{{user.icon}}</v-icon>
<span class="px-1">{{user.name}}</span>
<span class="px-1">{{user.age}}</span>
</div>
</v-expansion-panel-content>
</v-expansion-panel>
<v-dialog max-width="600px" v-model="dialog">
<v-btn fab slot="activator" class="primary mb-3">
<v-icon>fa-user-plus</v-icon>
</v-btn>
<v-card>
<v-card-title>
<h2>Add a New User</h2>
</v-card-title>
<v-card-text>
<v-form class="px-3" ref="form">
<v-text-field label="Name" v-model="user.name" prepend-icon="person"></v-text-field>
<v-text-field label="Age" v-model="user.age" prepend-icon="fa-heart"></v-text-field>
<div>
<v-btn flat icon v-for="(icon, index ) in icons" :key="index" #click="appendIcon()">
<v-icon>{{icon}}</v-icon>
</v-btn>
</div>
<v-btn
flat
class="primary mx-0 mt-3"
#click="addUser(user);
dialog=!dialog"
>Add user</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
methods: {
addUser: function(user) {
this.users.push(user);
this.user = {
name: undefined,
age: undefined,
icon: undefined,
};
console.log(user.name + " added to list");
},
appendIcon: function() {
console.log(this.icons[0]);
}
},
data() {
return {
dialog = fa
users: [],
user: {
name: undefined,
age: undefined,
icon: undefined,
},
icons: [
"fas fa-user",
"far fa-user",
"fas fa-user-cog",
]
};
}
};
</script>
In your buttons for your icons array if you add the individual icon as a parameter you can assign that to your user object. Like so:
#click="appendIcon(icon)"
and the method:
appendIcon(icon) {
this.user.icon = icon
console.log(icon);
}
Then when you call addUser() you can use the already set user object, so you don't need to pass that as a parameter.
#click="addUser";
and that method:
addUser() {
this.users.push(this.user);
this.user = {
name: undefined,
age: undefined,
icon: undefined,
};
console.log(user.name + " added to list");
},

Showing v-menue's selected option in another part of the application. Vuetify

So I have a v-menu with some options. Now I want to display the selected option in another part of my app (same component). I tried to do it using v-model but it doesn't work. What's the best way to do it?
This is the code for the v-menu and where I want to display the selected option:
<v-menu bottom transition="scale-transition" >
<v-btn slot="activator">​
28
</v-btn>
<v-list>
<v-list-tile
v-for="(item, index) in PIFBitems"
:key="index"
v-model="hasan"
#click="boardSwitch('shoPFIB', index)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
.
.
.
<p class="chipPam13"
>{{this.hasan}}</p>
.
.
This is the script code:
data() {
return {
hasan:'',
PIFBitems:[
{title: empty},
{title: PIFB}
]
}
}
Please use hasan rather than this.hasan in your HTML:
<p class="chipPam13">{{hasan}}</p>
Or if v-model doesn't work, you can try to set hasan value at boardSwitch function:
...
methods: {
boardSwitch (firstArg, secondArg, value) {
...
this.hasan = value
},
...
}
Please don't forget to add third argument to your function call in HTML:
<v-list-tile
v-for="(item, index) in PIFBitems"
:key="index"
v-model="hasan"
#click="boardSwitch('shoPFIB', index, item.title)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>

Categories