1👍
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.