I am using Vuetify card with a layout and rendering some dynamic vuetify components inside of the card on checkbox selection which renders either a divider, a spacer, toolbar or button but i am not able to figure out how can i make the buttons span the entire width?
Basically the dynamic button should look like the button at the end rendering the entire width.
Please check this codepen.
Please check this working example:-
new Vue({
el: "#app",
data() {
return {
pricing: [{
text: "Actual price:",
value: "$17,000",
},
{
text: " Discount",
value: "$12,345",
}
],
elements: [{
title: "Divider",
value: "v-divider"
},
{
title: "Toolbar",
value: "v-toolbar"
},
{
title: "Button",
value: "v-btn"
}
],
selected: []
};
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link rel="stylesheet" href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout row>
<v-flex xs6>
<v-card>
<v-card-text>
<v-layout row justify-space-between v-for="option in pricing" :key="option.value" class="my-3">
<span :class="option.class">{{option.text}}</span>
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
<span>{{option.value}}</span>
</v-layout>
<v-layout row justify-center>
<v-flex xs11>
<v-btn block>
Request
</v-btn>
</v-flex>
</v-layout>
</v-card-text>
</v-card>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el" v-model="selected" :label="el.title">
</v-checkbox>
</v-flex>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
Any help will be appreciated. Thank you so much.
Use .flex.xs12 (12 = flex-basis: 100%;)
-or-
remove xs12 (And add button block attribute = flex: 1 0 auto;).
<!-- block buttons extend the full available width -->
<template>
<v-btn block>
Block Button
</v-btn>
</template>
https://vuetifyjs.com/en/components/buttons/#block
Related
I am creating a page that consists of multiple cards, each card has a v-expand-transition and I am creating all cards in a v-for loop. The problem is that if I click one v-expand-transition then all of them open. I understand that it is because all of them are connected to the same "show", but I am not sure how to split that up so each one has their own event. My code is here:
<template>
<v-container>
<h1 class="font-weight-medium pa-6">All Labs</h1>
<v-row dense>
<v-col v-for="card in cards" :key="card.title" :cols="card.flex">
<v-card class="mx-auto" max-width="350">
<v-img class="white--text align-end" height="200px" :src="card.src" gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)">
<v-card-title v-text="card.title"></v-card-title>
</v-img>
<v-card-subtitle class="pb=0" v-text="card.location"></v-card-subtitle>
<v-card-text class="text--primary">
<div v-text="card.hours"></div>
<div v-text="card.keycardInfo"></div>
</v-card-text>
<v-card-actions>
<v-btn color="blue" :href="card.directions" text target="_blank">Directions</v-btn>
<v-btn color="blue" :to="card.page" text>Learn More</v-btn>
<v-spacer></v-spacer>
<v-btn icon #click="show = !show">
<v-icon>{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down'}}</v-icon>
</v-btn>
</v-card-actions>
<v-expand-transition>
<div v-show="show">
<v-divider></v-divider>
<v-card-text v-text="card.bottomInfo"></v-card-text>
</div>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
and my script is here:
<script>
import App from '../App.vue'
export default {
components: { App },
name: 'Home',
data: () => ({
show: false,
cards: [],
}),
}
</script>
I emptied the cards to avoid cluttering the page.
What happens is that since you are using a single variable to control the state of your component, the action will end up reflecting for everyone. One alternative would be to add a "show" property inside each object in your list, making each object have its own state. Here is an example of how it would look:
new Vue({
el: '#app',
data() {
return {
cards: [{
title: "My title",
flex: 6,
src: '#',
location: '#',
hours: '13',
keycardInfo: 'Info',
directions: '#',
page: '#',
to: '#',
bottomInfo: 'Bottom info',
show: false,
},
{
title: "My title 2",
flex: 6,
src: '#',
location: '#',
hours: '13',
keycardInfo: 'Info 2',
directions: '#',
page: '#',
to: '#',
bottomInfo: 'Bottom info 2',
show: false,
}],
}
}
})
<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">
<div id="app">
<v-container>
<h1 class="font-weight-medium pa-6">All Labs</h1>
<v-row dense>
<v-col v-for="card in cards" :key="card.title" :cols="card.flex">
<v-card class="mx-auto" max-width="350">
<v-img class="white--text align-end" height="200px" :src="card.src" gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)">
<v-card-title v-text="card.title"></v-card-title>
</v-img>
<v-card-subtitle class="pb=0" v-text="card.location"></v-card-subtitle>
<v-card-text class="text--primary">
<div v-text="card.hours"></div>
<div v-text="card.keycardInfo"></div>
</v-card-text>
<v-card-actions>
<v-btn color="blue" :href="card.directions" text target="_blank">Directions</v-btn>
<v-btn color="blue" :to="card.page" text>Learn More</v-btn>
<v-spacer></v-spacer>
<v-btn #click="card.show = !card.show">
{{ card.show ? 'Hide' : 'Show' }}
</v-btn>
</v-card-actions>
<v-expand-transition>
<div v-show="card.show">
<v-divider></v-divider>
<v-card-text v-text="card.bottomInfo"></v-card-text>
</div>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</v-container>
</div>
<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>
As you are using Vuetify, another approach would be to use expansion panels, I'll leave the documentation link below for you to take a look.
https://vuetifyjs.com/en/components/expansion-panels/#usage
I am trying add the feature to add multiple workers when clicked on Add worker. The issue I am facing here is that when I put workers array inside the management then this feature doesn't work. But if puts workers array outside the management hash then it works. But I want it to be inside the management issue. I am getting the error cannot read the property push.
<div v-for="(worker, index) in management.workers" :key="index">
<v-container fluid>
<v-layout row wrap>
<v-flex xs12 md6 class="add-col-padding-right info-align">
<v-text-field
label='Name'
v-model="worker.name"
>
</v-text-field>
</v-flex>
<v-flex xs12 md6 class="add-col-padding-left info-align">
<v-text-field
label='Hours of work'
v-model="worker.hours_of_work"
>
</v-text-field>
</v-flex>
</v-layout>
<v-btn class="red-button next-btn" #click="deleteRow(index)">Delete</v-btn>
</v-container>
</div>
<v-btn class="red-button next-btn" #click="addRow">Add Workers</v-btn>
<script>
export default {
data () {
return {
management: {
workers: []
}
}
}
methods: {
addRow() {
this.management.workers.push({
name: '',
hours_of_work: '',
total: ''
})
},
deleteRow(index) {
this.management.workers.splice(index,1)
}
}
}
</script>
Code seems to work below:
new Vue({
el: "#app",
vuetify: new Vuetify(),
data() {
return {
management: {
workers: []
}
}
},
methods: {
addRow() {
this.management.workers.push({
name: '',
hours_of_work: '',
total: ''
})
},
deleteRow(index) {
this.management.workers.splice(index, 1)
},
getRows(){
console.clear()
console.log(this.management.workers)
}
}
});
<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.2.20/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<div v-for="(worker, index) in management.workers" :key="index">
<v-container fluid>
<v-layout row wrap>
<v-flex xs12 md6 class="add-col-padding-right info-align">
<v-text-field label='Name' v-model="worker.name">
</v-text-field>
</v-flex>
<v-flex xs12 md6 class="add-col-padding-left info-align">
<v-text-field label='Hours of work' v-model="worker.hours_of_work">
</v-text-field>
</v-flex>
</v-layout>
<v-btn class="red-button next-btn" #click="deleteRow(index)">Delete</v-btn>
</v-container>
</div>
<v-btn class="red-button next-btn" #click="addRow">Add Workers</v-btn>
<v-btn class="red-button next-btn" #click="getRows">View Workers</v-btn>
</v-app>
</div>
I'm having some issues to make an avatar picker works...
After click to select the avatar in not being replaced and with the error TypeError: Cannot read property 'src' of undefined at VueComponent.selectAvatar
I'm currently using Vuetify and the v-avatar component with a v-for to load all the images.
Any idea how to make it work?
HTML
<v-flex xs12 pt-0 pb-0>
<h1 class="title mb-4">User Details</h1>
<v-avatar
size="100px"
>
<img
:src="this.selectedAvatar"
alt="Avatar"
>
</v-avatar>
</v-flex>
<v-flex x12>
<v-btn
color="primary"
flat="flat"
small
#click="selectAvatarDialog = true"
class="avatar-btn"
>
Update avatar
</v-btn>
</v-flex>
<v-dialog
v-model="selectAvatarDialog"
max-width="80%"
>
<v-card>
<v-container fluid pa-2>
<v-layout row wrap align-center justify-center fill-height>
<v-flex xs6 sm4 md3 lg2 my-2 class="text-xs-center"
v-for="(avatar,i) in avatars"
:key="i">
<v-img
:src="avatar.src"
aspect-ratio="1"
width="100px"
max-width="100px"
min-width="100px"
class="dialog-avatar-img"
#click="selectAvatar()"
></v-img>
</v-flex>
</v-layout>
<v-card-actions class="mt-2">
<v-spacer></v-spacer>
<v-btn
color="primary"
flat="flat"
#click="selectAvatarDialog = false"
>
Cancel
</v-btn>
</v-card-actions>
</v-container>
</v-card>
</v-dialog>
JS
export default {
layout: 'default',
data() {
return {
selectAvatarDialog: false,
avatars: [
{src: require('#/assets/images/avatar-01.png') },
{ src: require('#/assets/images/avatar-02.png') },
{ src: require('#/assets/images/avatar-03.png') },
{ src: require('#/assets/images/avatar-04.png') },
{ src: require('#/assets/images/avatar-05.png') }
],
selectedAvatar: require('#/assets/images/avatar-01.png'),
}
},
methods: {
selectAvatar(){
this.selectedAvatar = this.avatar.src
console.log('Avatar selected')
}
}
}
Thank you
The problem is in your selectAvatar method where you are trying to use 'this.avatar' but it doesn't exist. The avatar in your for loop isn't passed to your script. You should do like this:
<v-img
...
#click="selectAvatar(i)"
></v-img>
And in your script:
methods: {
selectAvatar(i){
this.selectedAvatar = this.avatars[i].src
console.log('Avatar selected')
}
}
I'm using the combobox component of VuetifyJS and I need to add an icon in front of every entry in the drop down. How to do that?
Here is a CodePen example of the combobox: https://codepen.io/anon/pen/KBLXYO
HTML
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-layout wrap>
<v-flex xs12>
<v-combobox
v-model="select"
:items="items"
label="Select a favorite activity or create a new one"
></v-combobox>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
JS:
new Vue({
el: '#app',
data () {
return {
select: 'Programming',
items: [
'Programming',
'Design',
'Vue',
'Vuetify'
]
}
}
})
Use the item scoped slot.
<v-combobox
v-model="select"
:items="items"
label="Select a favorite activity or create a new one">
<template slot="item" slot-scope="data">
<v-icon>home</v-icon> {{data.item}}
</template>
</v-combobox>
Here is your pen updated.
FWIW, this is all covered in the documentation.
I created a simple Contact list with an input to add the contact items but after I add a few items it's not resizing.
I used this as an example and there is resizing but not in my code:
https://v2.vuejs.org/v2/guide/list.html
Could anyone help me with that?
Here is the Codepen:
https://codepen.io/fabiozanchi/pen/qoBpgd
Vue.component('contact-item', {
template: '\
<v-list-tile-title>\
<button #click="$emit(\'remove\')"><v-icon class="remove-email-icon" color="red">remove_circle</v-icon></button>\{{ title }}\
</v-list-tile-title>\
',
props: ['title']
})
new Vue({
el: '#contact-list',
data: {
newContact: '',
contacts: [],
nextContactId: 1
},
methods: {
addNewContact: function() {
this.contacts.push({
id: this.nextContactId++,
title: this.newContact
})
this.newContact = ''
}
}
})
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons" />
<link rel="stylesheet" type="text/css" href="https://unpkg.com/vuetify#1.0.5/dist/vuetify.min.css" />
<script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#1.0.5/dist/vuetify.min.js"></script>
<div id="contact-list">
<v-app>
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<v-toolbar color="blue" dark>
<v-toolbar-title class="text-xs-center">Contacts</v-toolbar-title>
</v-toolbar>
<v-container>
<v-text-field v-model="newContact" #keyup.enter="addNewContact" placeholder="Add new email contact email"></v-text-field>
</v-container>
<v-divider></v-divider>
<v-list class="resize-list">
<v-list-tile>
<v-list-tile-content>
<v-list-tile-title is="contact-item" v-for="(contact, index) in contacts" :key="contact.id" :title="contact.title" #remove="contacts.splice(index, 1)">
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-card>
</v-flex>
</v-layout>
</v-app>
</div>
Thank you!
Use v-for on v-list-tile component (see vuetify examples).
<v-list-tile
v-for="(contact, index) in contacts"
:key="contact.id"
>
That will produce multiple lis that you want from your examples (currently you only have one li element in list because of v-for on title, so that's why it's not working properly)