In a component template I have the following code:
<v-col cols="6" v-for="(value, idx) in data[workingYear].monthValues" :key="idx">
{{ idx }}
<v-row class="ai-center">
<!-- Month -->
<v-col cols="2">{{
dayjs(idx + 1, "M").format("MMM").ucfirst()
}}</v-col>
<!-- Value -->
<v-col cols="10">
<v-text-field
class="mt-0 pt-0"
hide-details="auto"
min="0"
suffix=",00"
type="number"
v-model="data[workingYear].monthValues[idx]"
:label="$t('set')"
:prefix="getCurrency(true)"
:ref="'monthValue' + idx"
:rules="[rules.required, rules.invalid]"
/>
</v-col>
</v-row>
</v-col>
data[workingYear].monthValues is initialized as new Array(12).fill("") so it is an array of 12 empty string elements; ucfirst() is a custom extension to String.prototype that capitalize the first char of a string.
I'm aspecting to find in the first v-col block an incremented month, but the result is the following:
So, why {{ idx }} is incremented for every cycle as aspected but the month is always January? How can I fix this?
It seems that dayjs wants only strings as input date so write this is the solution:
dayjs("" + (idx + 1), "M").format("MMM").ucfirst()
By the way, at this point, the solution posted by Boussadjra Brahim is more elegant and readable, so +1 for the function.
Thanks
I suggest to use a computed property that returns a function which takes the index as parameter and return the month:
<v-col cols="2">{{
getMonth(idx)
}}</v-col>
script:
computed:{
getMonth(){
return (idx)=>dayjs(`${idx + 1}`, "M").format("MMM").ucfirst()
}
}
Related
I am doing this excercise in vue.js 2.6.
I have a toggled button that has two values: '1' or '2', and I made a computed that depending on these previous values return other values.
this returns either '1' or '2'
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Toggle button</label><br />
<v-btn-toggle v-model="backendprop.prop1" color="blue" class="form-control p-0" dense borderless>
<v-btn v-for="option in BackendProp1" :key="option.value" :value="option.value">{{ option.label }}</v-btn>
</v-btn-toggle>
</v-col>
I want the value of this input to update according to computed setValueBecauseToggledButton
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Value depending on Toggled Button</label><br />
<v-text-field
v-model="backendprop.prop2"
type="text"
disabled
outlined
dense
:value="setValueBecauseToggledButton"
/>
</v-col>
and this is the computed value:
computed:{
setValueBecauseToggledButton(){
return this.backendprop?.prop1?.toString() === '2' ? 'Valid prop' : ''
}
The behavior I expect is when I choose between the options of one input the other input should be updated.
Placing console.log in setValueBecauseToggledButton shows me that is working perfectly, but it does nothing on the v-text-field.
You could set a watcher on your property and then update the value for the v-text-field inside it.
<v-col cols="12" sm="12" md="4" lg="4" xl="4">
<label>Value depending on Toggled Button</label><br />
<v-text-field
v-model="backendprop.prop2"
type="text"
disabled
outlined
dense
/>
</v-col>
watch: {
'backendprop.prop1'(value){
this.backendprop.prop2 = value.toString() === '2' ? 'Valid prop' : ''
}
}
I'm trying to do load more function. When load more button is clicked show next 10 hidden items in v-for allCategories loop.
<template v-for="(category, i) in allCategories">
<v-col :key="i" v-show="i <= 10" class="col-6 col-sm-4">
<v-checkbox
dense
color="black"
:label="category.title"
:value="isCategoryChecked(category.id)"
#click="() => selectCategory(category.id)"
/>
</v-col>
</template>
load more button
<v-btn color="black white--text"
#click="showMoreCategories"
:loading="loading">
{{ $t('general.loadMore') }}
</v-btn>
showMoreCategories function
showMoreCategories() {
}
How do i implement this?
Assuming your variable allCategories contains all the categories you could possibly want (i.e. you don't have to fetch additional categories from a server or local store) then you can replace v-show="i <= 10" with v-show="i <= numberOfCategoriesToShow". Where numberOfCategoriesToShow is a new variable you have defined and initially set to 10.
Then your showMoreCategories function would look like this
showMoreCategories() {
this.numberOfCategoriesToShow += 10;
}
I have an issue on my edit page while trying to prepopulate date range value.
Ex. 2022-06-03, 2022-06-04
Rather than see this
I got an error in the console.
I don't know if I understood the question correctly, but in the absence of a code snippet I refer to the official Vuetify documentation.
Basically you assign a date pattern to the Vuetify component and optionally, with a computed, calculate the divisor.
export default {
data: () => ({
dates: ['2019-09-10', '2019-09-20'],
}),
computed: {
dateRangeText () {
return this.dates.join(' ~ ')
},
},
}
<v-row>
<v-col
cols="12"
sm="6"
>
<v-date-picker
v-model="dates"
range
></v-date-picker>
</v-col>
<v-col
cols="12"
sm="6"
>
<v-text-field
v-model="dateRangeText"
label="Date range"
prepend-icon="mdi-calendar"
readonly
></v-text-field>
model: {{ dates }}
</v-col>
</v-row>
I have what seems to be a very common issue, but I can get over it.
I have an API query that returns me a list of object.
I want to display it my page as a grid of card filled with the content.
I want my grid to be in 5 column, and the number of row will adapt to the number of element in my list.
I can figure out how to achieve it.
For example: i have a query returning
items[
{"id":1,"title":"title1,"description":"description1"}
{"id":2,"title":"title2,"description":"description2"}
{"id":3,"title":"title3,"description":"description3"}
{"id":4,"title":"title4,"description":"description4"}
{"id":5,"title":"title5,"description":"description5"}
{"id":6,"title":"title6,"description":"description6"}
{"id":7,"title":"title7,"description":"description7"}
]
My grid as to be made from 7 elements with systematically 5 columns and adaptive rows like:
And if my query returns for example 14 elements, the layout should adapt to look like this:
The closest I was able to get with the code was.
<v-container class="mt-2">
<h1>Top Rated views</h1>
<v-row v-for="n in gridDivider" :key="n" class="n === 1 ? 'mb-6' : ''">
<v-col v-for="(item,index) in Items" :key="index">
<v-card class="mx-auto" max-width="300">
<v-img
class="white--text align-end"
height="200px"
src="item.avatar"
>
<v-card-title>anything as text</v-card-title>
</v-img>
<v-card-subtitle class="pb-0"> Number 10 </v-card-subtitle>
<v-card-text class="text--primary">
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
Thanks for helping
It could be done if you change v-row and v-col declarations this way:
<v-row class="five-cols">
<v-col v-for="(item,index) in Items" :key="index">
...
and create a CSS class five-cols using CSS Grid Layouts:
.five-cols {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
Example at CodePen
Im trying to make an infinite scroll list but it's really not lazy loading, been stuck with this for hours, the whole list will come in.
.....
<v-col
v-for="(post, i) in posts"
:key="i"
cols="12"
>
<v-lazy
v-model="isActive"
:options="{
threshold: .5
}"
transition="fade-transition"
>
{{Content here}}
</....
API used for test : https://jsonplaceholder.typicode.com/posts
There is a new virtual-scroller component, but it doesn't work with responsive content like grid rows/cols. Instead use v-lazy...
I discovered that the columns need to have defined min-height (approx. to the expected height of the cards) in order for the v-lazy intersection observer to work. Use something like a v-sheet or v-responsive to set the min-height and contain the cards.
Also bind the v-model of the v-lazy to each post (ie: post.isActive), instead of a global isActive var...
<v-col lg="3" md="4" sm="6" cols="12" v-for="(post, index) in posts">
<v-sheet min-height="250" class="fill-height" color="transparent">
<v-lazy
v-model="post.isActive" :options="{
threshold: .5
}"
class="fill-height">
<v-card class="fill-height" hover>
<v-card-text>
<v-row :key="index" #click="">
<v-col sm="10" cols="12" class="text-sm-left text-center">
#{{ (index+1) }}
<h2 v-html="post.title"></h2>
<div v-html="post.body"></div>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-lazy>
</v-sheet>
</v-col>
Demo: https://codeply.com/p/eOZKk873AJ
I can suggest another solution with v-intersect, which works perfect for me.
Sorry, the snippet may be not working as composed of my code, but the idea should be pretty clear
<template>
<v-list class="overflow-y-auto" max-height="500">
<v-list-item v-for="item in items">
{{ item.name }}
</v-list-item>
<v-skeleton-loader v-if="moreDataToAvailable" v-intersect="loadNextPage" type="list-item#5" />
</v-list>
</template>
<script lang="ts">
import Vue from 'vue'
const pageSize = 10
export default Vue.extend({
data(): any {
return {
pageLoaded: 0,
totalCount: 100,//fetch from API
items: []
}
},
computed: {
moreDataToAvailable (): boolean {
return Math.ceil(this.totalCount / pageSize) - 1 > this.pageLoaded
}
},
methods {
async loadNextPage (entries: IntersectionObserverEntry[]) {
if (entries[0].isIntersecting && this.moreDataToAvailable) {
const nextPage = this.pageLoaded + 1
const loaded = await this.loadPage(nextPage) //API call
loaded.data.forEach((item: any) => this.items.push(item))
this.totalCount = loaded.totalCount
this.pageLoaded = nextPage
}
},
}
})
</script>