Apply condition class to v-col - vue.js

I'm trying to apply condition class to my v-col
<v-row v-for="(rule, index) in ruleDetails" :key="index">
<v-col
:class="{
'md-4': rule.width == 'large',
'md-3': rule.width == 'medium'
}"
>
</v-col>
</v-row
and rule.width = 'medium' right now.
It doesn't seem to take any effect.
Did I forget something ?

You can make it an array.
<v-row v-for="(rule, index) in ruleDetails" :key="index">
<v-col :class="[rule.width == 'large' && 'md-4', rule.width == 'medium' && 'md-3']">
</v-col>
</v-row
This resolves in :class="[false, 'md-3'] which Vue parses to <foo class="md-3" />
const rule = {
width: 'medium'
}
console.log([rule.width == 'large' && 'md-4', rule.width == 'medium' && 'md-3'])

You can use md attribute directly in <v-col> instead of class. To achieve this, You can apply one more property as value along with width in each object.
Demo (Run this code snippet in full page) :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
ruleDetails: [{
width: 'small',
value: 2
}, {
width: 'medium',
value: 3
}, {
width: 'large',
value: 4
}]
}),
});
#app { padding: 1% 5% }
<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>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css"/>
<div id="app">
<v-row v-for="(rule, index) in ruleDetails" :key="index">
<v-col :md="rule.value" style="background-color: yellow">
{{ rule.width }}
</v-col>
</v-col>
</v-row>
</div>

Related

V-select issue in Vuetify 3

I'm using Vuetify 3.0.0-beta.0 ~ for my project (because it is the only version that supports vue3), and having a bit weird issue
I want to implement the same thing as described there https://codepen.io/reijnemans/pen/vYNadMo?editors=1010 with v-select involved, so I was needed to use Vuetify
copied snippet
<v-select
:items="items"
label="Standard"
>
<template v-slot:selection="{ item, index }">
<img :src="item.image">{{ item.name }}</template>
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}</template>
</v-select>
My Component:
<template>
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
:items="items"
label="Standard">
<template v-slot:selection="{ item }">
<img :src="item.image">{{ item.name }}
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}
</template>
</v-select>
</v-col>
</v-col>
</div>
</template>
<script>
import { mapState } from "vuex";
/* eslint-disable */
export default {
name: "testComponent",
data() {
return {
// hardware Configuration Validation Rules
items: [
{ name: 'Foo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Bar', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Hoo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Coo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'}],
}
}}
When I'm trying to run the above component I always get this weird error Failed setting prop "type" on <select>: value text is invalid. TypeError: Cannot set property type of #<HTMLSelectElement> which has only a getter,
Did anyone faced similar issue before?
In Vuetify 3, you need some workarounds to style the items in v-select, because the item slot resets the entire styling.
You should use the menu-props, with it you can pass props through to the v-menu component. It accepts an object with anything from /api/v-menu. This allows you to close the field on click.
In the item slot, you should use a v-list-item with an #click property to set the model.
I made an example here with a selection of symbols:
<script setup>
const symbols = [
'ab-testing',
'abacus',
'account',
'account-alert',
]
const form = { symbol: '', }
</script>
<template>
<v-select
v-model="form.symbol"
:items="symbols"
label="Symbol"
:prepend-inner-icon="'mdi-'+form.symbol"
:menu-props="{
closeOnClick: true,
closeOnContentClick: true,
}"
>
<template v-slot:selection="{ item, index }">
{{ item.value }}
</template>
<template v-slot:item="{ item, index }">
<v-list-item
:title="item.title"
:prepend-icon="'mdi-'+item.title"
#click="form.symbol = item.title"
>
</v-list-item>
</template>
</v-select>
</template>
I hope it helps you.
I couldn't find correct solution but I just wanted to share what I did about scoped slot. I think we should use item.raw to access name and image. And the next problem is how to make it clickable to trigger select event that I didn't know yet :(
const { createApp } = Vue
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const app = createApp({
data() {
return {
value: null,
items: [
{
name: 'Foo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Bar',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Hoo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Coo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
}
]
}
}
});
app.use(vuetify).mount('#app');
<link href="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.js"></script>
<div id="app">
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
v-model="value"
:items="items"
item-title="name"
item-value="name"
label="Standard">
<template v-slot:item="{item}">
<v-list-item
:prepend-avatar="item.raw.image"
:title="item.raw.name"
/>
</template>
</v-select>
</v-col>
</v-col>
</div>
</div>

How to search charged option in a v-select

i have this v-select whose items charge dinamicaly, the user can choose several options from it, the problem is i have to many options and i want the user can search the option that he/she wants writing text:
<v-col cols="7">
<v-select
v-model="fillModReparacion.listamanodeObraC"
:items="fillModReparacion.listamanodeObra"
item-value="itg_id"
item-text="itg_descripcion"
attach
chips
label="Mano de Obra"
multiple
outlined
clearable
return-object
></v-select>
</v-col>
You can use v-slot:prepend-item to prepend the search before the options list inside v-select.
Live Demo :
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
searchTerm: "",
fruits: [
"Apples",
"Apricots",
"Avocado",
"Bananas",
"Blueberries",
"Blackberries",
"Dates",
"Eggplant",
"Figs",
"Grapes",
"Grapefruit",
"Guava"
],
fruitsCopy: [],
selectedFruits: []
}),
mounted() {
this.fruitsCopy = [...this.fruits];
},
computed: {},
methods: {
searchFruits(e) {
if (!this.searchTerm) {
this.fruits = this.fruitsCopy;
}
this.fruits = this.fruitsCopy.filter((fruit) => {
return fruit.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
});
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.21/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.2.21/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css"/>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-select v-model="selectedFruits" :items="fruits" attach label="Favorite Fruits" multiple>
<template v-slot:prepend-item>
<v-list-item>
<v-list-item-content>
<v-text-field v-model="searchTerm" placeholder="Search" #input="searchFruits"></v-text-field>
</v-list-item-content>
</v-list-item>
<v-divider class="mt-2"></v-divider>
</template>
</v-select>
</v-container>
</v-app>
</div>

Vuetify - Outline color set programatically

Does anyone know how to programatically set the outline color on a v-text-field ?
I was thinking something along the lines of
<v-text-field v-model="value" :class="value === 0 ? greenStyle : regularStyle"/>
<style>
.greenStyle {
color: green
},
.redStyle {}
</style>
You can use color attribute like this : :color="!value ? 'green' : 'red'"
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
value: null
}
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-container>
<v-text-field
label="Outlined"
outlined
v-model="value"
:color="value === '0' ? 'green' : 'red'"
></v-text-field>
</v-container>
</v-app>
</div>

How do I lazy load item lists on Vuejs and Vuetify's lazyload?

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>

Vuetify - How to add html in slider tick labels

I am using Vuetify in my vue app and need to give HTML tags in my tick labels, I checked Vuetify doc but found it accepts string and in case we pass HTML, it renders it as string. Is there a way we can inject HTML in tick labels. Here is what I have tried:
Codepen link here: https://codepen.io/vishalgulati/pen/gOYyMza?&editable=true&editors=101
<div id="app">
<v-app id="inspire">
<v-card flat color="transparent">
<v-subheader>Tick labels</v-subheader>
<v-card-text>
<v-slider
v-model="fruits"
:tick-labels="ticksLabels"
:max="3"
step="1"
ticks="always"
tick-size="2"
></v-slider>
</v-card-text>
</v-card>
</v-app>
</div>
new Vue({
el: '#app',
data () {
return {
value: 0,
fruits: 0,
ticksLabels: [
'<span>&nbsp</span>',
'',
'Pear',
'Apple'
]
}
}
})
Use template slot for thumb-label. Found in their documents:
<div id="app">
<v-app id="inspire">
<v-row>
<v-col class="pa-12">
<v-range-slider
:tick-labels="seasons"
:value="[0, 1]"
min="0"
max="3"
ticks="always"
tick-size="4"
>
<template v-slot:thumb-label="props">
<v-icon dark>
{{ season(props.value) }}
</v-icon>
</template>
</v-range-slider>
</v-col>
</v-row>
</v-app>
</div>
...
data: () => ({
seasons: [
'Winter',
'Spring',
'Summer',
'Fall',
],
icons: [
'mdi-snowflake',
'mdi-leaf',
'mdi-fire',
'mdi-water',
],
}),
methods: {
season (val) {
return this.icons[val]
},
},
})
source: https://vuetifyjs.com/en/components/sliders#custom-range-slider
codepen: https://codepen.io/pen/?&editable=true&editors=101