Vue v-select problem with v-slot not showing text - javascript

I'm trying to display custom text in v-select options by slots.
Template:
<v-select v-model="dLevelSelected" :items="dLevels" solo>
<template slot="item" slot-scope="data">
<span>{{data.description}}</span>
</template>
</v-select>
Script:
data () {
return {
dLevelSelected: null,
dLevels: [{id:1, value: 1, description: 'Level1'}, {id:2, value: 2, description: 'Level2'}]
}
}
With this, when you open the v-select the two registers of dLevels are appearing as boxes but with any text. It seems like the data.description is being evaluated like data.undefined
Thanks!

slot and slot-scope are deprecated as of Vue 2.6.0.
The new slot syntax combines those two props into v-slot, so the equivalent item slot is:
<template v-slot:item="scope">
<span>{{ scope.item.description }}</span>
</template>
Note the scope contains an item property that can be used to access description. You can use object destructuring to simplify that to:
<template v-slot:item="{ item }">
<span>{{ item.description }}</span>
</template>
Similarly, you'll probably want a custom selection slot that renders the appearance of the selected item:
<template v-slot:selection="{ item }">
<span>{{ item.description }} ({{ item.value }})</span>
</template>
The final template should look similar to this:
<v-select v-model="dLevelSelected" :items="dLevels" solo>
<template v-slot:item="{ item }">
<span>{{ item.description }}</span>
</template>
<template v-slot:selection="{ item }">
<span>{{ item.description }} ({{ item.value }})</span>
</template>
</v-select>
demo

Related

Dynamically create Vue Component on click

I have a list of orders which I am populating via the orders array. Each of these orders have a functionality where the user can edit these orders. I am trying to generate a vuetify dialog box component when the user clicks on the edit button which will have the default data from that order which the user can choose to edit. So far I have tried this,
<tbody class="items">
<tr v-for="order in orders" :key="order.name">
<td>{{ order.fullname }}</td>
<td>{{ order.address }}</td>
<td>{{ order.phone }}</td>
<!-- <td>{{ order.orderQuantity }}</td> -->
<td>{{ order.quantity }}</td>
<td v-if="order.status == true">
<v-chip small outlined class="ma-2 chip" color="green">delivered</v-chip>
</td>
<td v-if="order.status == false">
<v-chip small outlined class="ma-2 chip" color="red">in progress</v-chip>
</td>
<td>
<!-- <component v-bind:is="component"></component> -->
<!-- <EditOrder></EditOrder> -->
<v-dialog v-model="dialog" persistent max-width="290">
<template #activator="{ on, attrs }">
<v-btn icon color="primary" dark v-bind="attrs" v-on="on"> Open Dialog </v-btn>
</template>
<v-card>
<v-card-title class="headline"> Use Google's location service? </v-card-title>
<v-card-text>{{ phone }}</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" text #click="dialog = false"> Disagree </v-btn>
<v-btn color="green darken-1" text #click="dialog = false"> Agree </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</td>
</tr>
</tbody>
but this generates n instances of the dialog box before the actual components loads. I also tried using async components but couldn't figure out where I was wrong.
This is what I think should happen;
When the user clicks on the "edit order" button, a dialog box component with the default order details for that particular order must be automatically generated and destroyed.
Please correct me if I am wrong.
Move the dialog part to a separate component
In the parent component, use it once at the beginning with dialog=false to be hidden initially
Add a data attribute orderToEdit which will be a prop to the child component
For each order in the list, add an edit button that would call a method when clicked passing the order
In this method, set orderToEdit to the passed order of the clicked item and set dialog=true to show it with the custom values
const dialogmodel = Vue.component('btn', {
template: '#dialogmodel',
props: { order: Object, value: Boolean },
computed: {
dialog: {
get () { return this.value; },
set (value) { this.$emit('close', value); }
}
}
});
new Vue({
el:"#app",
vuetify: new Vuetify(),
components: { dialogmodel },
data: () => ({
orders: [
{ name:"1", fullname:"fullname1", address:"address1", phone:"phone1", quantity:"quantity1", status:false },
{ name:"2", fullname:"fullname2", address:"address2", phone:"phone2", quantity:"quantity2", status:true }
],
dialog:false,
orderToEdit: {}
}),
methods: {
closeDialog(value) { this.dialog = value; },
editOrder(order) { this.orderToEdit = order; this.dialog = true; }
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<template id="dialogmodel">
<div>
<v-dialog v-model="dialog" max-width="290" persistent>
<v-card>
<v-card-title class="headline">
{{ order.fullname }}
</v-card-title>
<v-card-text> {{ order.address }} </v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" text #click="$emit('close')">
Disagree
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<v-app id="app">
<div>
<dialogmodel v-model="dialog" :order="orderToEdit" #close="closeDialog" />
</div>
<div>
<table>
<tbody class="items">
<tr v-for="order in orders" :key="order.name">
<td>{{ order.fullname }}</td>
<td>{{ order.address }}</td>
<td>{{ order.phone }}</td>
<td>{{ order.quantity }}</td>
<td v-if="order.status == true">
<v-chip small outlined class="ma-2 chip" color="green">delivered</v-chip>
</td>
<td v-if="order.status == false">
<v-chip small outlined class="ma-2 chip" color="red">in progress</v-chip>
</td>
<td>
<v-btn #click="editOrder(order)">Edit</v-btn>
</td>
</tr>
</tbody>
</table>
</div>
</v-app>
Are you looking to have a central popup being filled with the data of the order you selected to edit? In that case you can simply have a single component for the edit popup (instead of adding them to your v-for).
You can do it like this:
When clicking on 'edit', set a data property 'orderIndexToEdit' to the index of the order in the v-for
have a single dialog box that becomes visible when 'orderIndexToEdit' is truethy using v-if or v-show
Create a computed property that returns the correct order from the orders array, based on the index stored in the 'orderIndexToEdit' variable.
Use that computed property to populate the dialog box.
Let me know whether this helps!

Create new row for every 3 items Vue.js

Basically the code works fine but I am not able to change the order of the elements. At the moment the result looks like this:
But actually I would like it like this:
My code Looks like this:
<template>
<div class="home">
<el-container>
<el-row v-for="story of chunkedItems" :key="story.id">
<el-col v-for="item of story" :key="item.id">
<el-card>
<div>{{ item.title }}</div>
<div>{{ item.text }}</div>
</el-card>
</el-col>
</el-row>
</el-container>
</div>
</template>
computed: {
chunkedItems() {
return this.$_.chunk(this.stories, 3);
},
},
Any suggestion is appreciated.
Remove the chunk and use :span="8" instead.
<template>
<div class="home">
<el-container>
<el-row>
<el-col :span="8" v-for="item of stories" :key="item.id">
<el-card>
<div>{{ item.title }}</div>
<div>{{ item.text }}</div>
</el-card>
</el-col>
</el-row>
</el-container>
</div>
</template>
computed: {
},

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.

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>

How to break a v-for loop in vuejs

I have a code segment that i have mentioned below. I have used vuejs with vuetifyjs.
<v-data-table v-bind:headers="headers" v-bind:items="uniqueSubjects">
<template slot="items" slot-scope="props">
<td class="text-xs-center">{{ props.index+1 }}</td>
<td class="text-xs-center">{{ month[new Date(props.item.daily_date).getMonth()] }},{{ props.item.student_id }}</td>
<td class="text-xs-center">{{ props.item.subjects.subject_name }}{{ props.item.subjects.id }}</td>
<template v-for="n in 31">
<template v-for="(mark,index) in resultsList">
<template v-if="new Date(mark.daily_date).getDate() == n && mark.subject_id == props.item.subject_id && mark.student_id == props.item.student_id">
<td class="text-xs-center">
{{ mark.daily_marks }}
</td>
</template>
<template v-else-if="index>=resultsList.length-1">
<td class="text-xs-center">-</td>
</template>
</template>
</template>
</template>
<template slot="pageText" slot-scope="{ pageStart, pageStop }">
From {{ pageStart }} to {{ pageStop }}
</template>
</v-data-table>
I want to break my <template v-for="(mark,index) in resultsList"> loop when the internal v-if condition is true.
Here i want to search the inner loop from first to last.I want to break the loop if the data is matched depending on the given condition.and then i want to do it again and again.
How can I do that? Any help would be appreciated.
Thanks in advance.
There is no way to break v-for. It is better to create a computed property in your component and filter your data there to pass only needed data to v-for.
For example:
// ... your component code
computed: {
validResultsList() {
return this.resultsList/* ... your filtering logic ... */;
}
}
// ... your component code
And then in your template:
<template v-for="(mark,index) in validResultsList">

Categories