Prevent switch toggle and show alert message v-switch in Vuetify - vue.js

I'm facing a problem to prevent the toggle for the v-switch and show an alert message. Here is
Codepen example
If I add CSS to prevent the toggle, then click event is not working
.v-input--switch {
pointer-events: none;
}
Also, if I add disabled prop to switch, then click event is not working
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
switch1: true,
snackbar: false
}
},
methods:{
showALert(){
this.snackbar = true;
}
}
})
.v-input--switch .v-input--switch__thumb {
color: black !important;
}
.v-input--switch .v-input--switch__thumb.primary--text {
color: black !important;
}
.v-input--switch .v-input--switch__track.primary--text {
color: rgba(0, 0, 0, 0.38) !important;
}
.v-input--switch.v-input--is-disabled:not(.v-input--is-dirty) .v-input--switch__thumb {
color: black !important;
}
.v-input--switch .v-input--switch__thumb:after {
content: "£";
color: #fff;
}
//.v-input--switch {
// pointer-events: none;
//}
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#5.x/css/materialdesignicons.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.3.14/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.3.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container class="px-0" fluid>
<v-switch :ripple="false" flat #change="showALert"></v-switch>
<v-snackbar v-model="snackbar" bottom right>
This has been set to Historical Mode
<template v-slot:action="{ attrs }">
<v-icon v-bind="attrs" color="white" small #click="snackbar = false">
mdi-close
</v-icon>
</template>
</v-snackbar>
</v-container>
</v-app>
</div>
Can someone help me with this? Any solutions would be appreciated.

You can use the readonly prop of the v-switch which prevents toggling of the switch when clicked. You can also add #click directly on v-switch to handle whatever behavior you want to happen when the switch is clicked like showing an alert or validating a value before toggling the switch programmatically.
<v-switch #click="showALert" readonly></v-switch>

Related

vue clicking on the action button's focus area breaks it

I'm trying to create a floating action button by using vuetify -vspeed dial. I created a logic to style my button whenever it's clicked and it's working perfect, it collapses and expands whenever i click on it. However, if i try to click the focus area of the action buttons, it breaks it and close the buttons. How can i prevent that? When I click on button, it's fine - I use click.stop to make it persistent but if i click to the area right next to button, it closes the buttons which breaks my logic for styling. Here's my code
Test.Vue
<template>
<v-card :class="{create: backgroundColor }">
<v-speed-dial
:bottom="true"
:right="true"
:direction="direction"
:transition="transition"
fixed
>
<template v-slot:activator>
<v-btn
:class="{is_active:isActive}"
color="#C6002B"
fab
dark
#click=toggleButton
x-large
>
<v-icon>{{isActive? 'mdi-close' : 'mdi-account-circle'}}</v-icon><span>{{isActive ? "EXPANDED" : ''}}</span>
</v-btn>
</template>
<v-btn
v-if="finalProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func1')"
color="white" >
<v-icon color="#F0BE85">mdi-pencil</v-icon>
</v-btn>
<v-btn
v-if="thirdProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func2')"
color="white">
>
<v-icon color="purple">mdi-delete</v-icon>
</v-btn>
<v-btn
:class="{alignLeft:isActive}"
v-if="secondProp"
fab
dark
large
#click.stop="$emit('func3')"
color="white">
>
<v-icon color="green">mdi-plus</v-icon>
</v-btn>
<v-btn
v-if="firstProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func4')"
color="white">
>
<v-icon color="red">home</v-icon>
</v-btn>
</v-speed-dial>
</v-card>
</template>
<script>
export default {
name: 'FloatingButton',
props: {
firstProp: Boolean,
secondProp: Boolean,
thirdProp: Boolean,
finalProp: Boolean
},
data: () => ({
direction: 'top',
fab: false,
right: true,
bottom: true,
transition: 'scale-transition',
isActive: false,
backgroundColor: false,
check:true
}),
methods: {
toggleButton:function() {
this.isActive = !this.isActive
this.backgroundColor = !this.backgroundColor
}
},
}
</script>
<style scoped>
.is_active {
min-width:120px
/* width: 380px;
height: 70px;
border-radius: 36px;
margin:5px; */
}
.is_active span {
font-size: 18px;
letter-spacing: 0px;
}
.create {
min-width: 100%;
min-height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 4;
background:rgba(0,0,0,0.4);
color:rgba(0,0,0,0.8);
}
}
</style>
App. vue
<template>
<v-app>
<Test :firstProp=a :secondProp=b :thirdProp=c :lastProp=d />
</v-app>
</template>
<script>
import Test from './components/Test'
export default {
name: 'App',
components: {
Test
},
data(){
return{
a:true,
b:true,
c:true,
d:true
}
}
};
</script>
I don't see what's wrong. Can you check this reproduction? I mostly only changed the casing of attributes on <Test> element.
Vue.component('Test', {
template: `
<v-card :class="{create: backgroundColor }">
<v-speed-dial
:bottom="true"
:right="true"
:direction="direction"
:transition="transition"
fixed
>
<template v-slot:activator>
<v-btn
:class="{is_active:isActive}"
color="#C6002B"
fab
dark
#click="toggleButton"
x-large
>
<v-icon>{{isActive? 'mdi-close' : 'mdi-account-circle'}}</v-icon>
</v-btn>
</template>
<v-btn
v-if="finalProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func1')"
color="white" >
<v-icon color="#F0BE85">mdi-pencil</v-icon>
</v-btn>
<v-btn
v-if="thirdProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func2')"
color="white">
>
<v-icon color="purple">mdi-delete</v-icon>
</v-btn>
<v-btn
:class="{alignLeft:isActive}"
v-if="secondProp"
fab
dark
large
#click.stop="$emit('func3')"
color="white">
>
<v-icon color="green">mdi-plus</v-icon>
</v-btn>
<v-btn
v-if="firstProp"
:class="{alignLeft:isActive}"
fab
dark
large
#click.stop="$emit('func4')"
color="white">
>
<v-icon color="red">home</v-icon>
</v-btn>
</v-speed-dial>
</v-card>
`,
props: {
firstProp: Boolean,
secondProp: Boolean,
thirdProp: Boolean,
finalProp: Boolean
},
data: () => ({
direction: 'top',
fab: false,
right: true,
bottom: true,
transition: 'scale-transition',
isActive: false,
backgroundColor: false,
check:true
}),
methods: {
toggleButton: function() {
this.isActive = !this.isActive
this.backgroundColor = !this.backgroundColor
}
},
})
Vue.config.productionTip = false
new Vue({
el: '#app',
vuetify: new Vuetify(),
data(){
return{
a:true,
b:true,
c:true,
d:true
}
}
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/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">
<style scoped>
.is_active {
/*min-width:120px
width: 380px;
height: 70px;
border-radius: 36px;
margin:5px; */
}
.is_active span {
font-size: 18px;
letter-spacing: 0px;
}
.create {
min-width: 100%;
min-height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 4;
background:rgba(0,0,0,0.4);
color:rgba(0,0,0,0.8);
}
}
</style>
</head>
<body>
<div id="app">
<v-app>
<Test :first-prop="a" :second-prop="b" :third-prop="c" :last-prop="d" />
</v-app>
</div>
</body>
</html>

How to disable carousel in v-tabs

I'm doing kind of horizontal navigation bar using v-tabs and v-tabs-items to switch between slides by clicking on the specific tab.
But Vuetify automatically adds carousel to v-tabs component. How can I disable it? I need to make v-tabs component multilined.
I tried to add v-tab inside v-item-group, but it loose all it's styles. Also, hide-slider didn't disable slider too.
<v-tabs v-model="tab" hide-slider>
<v-tab v-for="(item, index) of [1, 2, 3, ..., 100]" :key="index">
{{ item }}
</v-tab>
</v-tabs>
I should render elements like on this picture. If it haven't enought space to for element on current line - it should add it on next.
.v-tabs-bar__content {
flex-wrap: wrap;
width: 100%;
}
div.v-tabs-bar {
height: auto;
}
... will, most likely, solve your problem.
See it working:
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: [...Array(100).keys()].map(() => ['anything', 'whatever', 'something'][Math.floor(3 * Math.random())]),
}),
propsData: {
tab: {
type: Number,
default: 0
}
}
})
.v-tabs-bar__content {
flex-wrap: wrap;
width: 100%;
}
div.v-tabs-bar {
height: auto;
}
div.v-tab {
line-height: 3rem; /* or use padding instead */
}
<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#3.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.0.15/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.0.15/dist/vuetify.min.js"></script>
<div id="app">
<v-tabs>
<v-tab v-for="(item, index) in items" :key="index">
{{item}}
</v-tab>
</v-tabs>
</div>

Hide div when clicking the main div, but not when clicking child divs, hrefs, spans etc

So, when you click the blue content, I want to hide it, but not if you click a child element, like a h2, a, p, etc. Is this possible?
Please see the fiddle
html
<html>
<head></head>
<body>
<div id="app">
<div v-if="modal" id="content" #click="toggle">
<h3>
Name
</h3>
<span>
Like this (don't close if clicked)
</span>
</div>
<button #click="toggle">Toggle</button>
</div>
</body>
</html>
.js
new Vue({
el: '#app',
data: {
modal: true
},
methods: {
toggle: function( ){
this.modal = !this.modal
}
}
});
.css
a {
color: white
}
#content {
width: 300px;
height: 300px;
background: blue;
color: white;
}
Fiddle: http://jsfiddle.net/awu752mr/6/
I believe that is what the v-on:click.self modifier does. See here in the docs.
As #LShapz answered, the modifier=.self should be the recommended approach (Vue Style).
Another way is compare $event.target === $event.currentTarget (not recommended for your use case, but you may use these two properties for some other situations in future).
Vue.config.productionTip = false
new Vue({
el: '#app',
data: {
modal: true
},
methods: {
toggle: function(ev){
if(ev.target === ev.currentTarget) this.modal = !this.modal
}
}
});
a {
color: white
}
#content {
width: 300px;
height: 300px;
background: blue;
color: white;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div v-if="modal" id="content" #click="toggle($event)">
<h3>
Name
</h3>
<span>
Like this
</span>
</div>
<button #click="toggle">Toggle</button>
</div>

Vue + Vuetify expansion panel enter/leave animation

I'm currently developing a webapp in Vue.js with the help of Vuetify.
I found the expansion panel element very usefull and I wanted to use it in my website.
So I easily get the data i want to display from Firebase and i proceed to load the items with this template:
<v-expansion-panel popout>
<v-expansion-panel-content
v-for="doc in filteredclienti"
:key="doc.id">
<div slot="header">{{doc.data().Nome}} {{doc.data().Cognome}}</div>
<v-card>
Card content
</v-card>
</v-expansion-panel-content>
</v-expansion-panel
Everything works fine, the panel is ok and the popup animation works fine too.
Now I'd like to display a simple enter/leave animation to each item.
I tried to add a <transition-group> tag after the <v-expansion-panel popuot> but the console tells me want only a <v-expansion-panel-content> element.
So i tried to add <transition-group> inside <v-expansion-panel-content> but in this case the layout is no more correct and the popup animation is not working anymore.
How can i do it? Thanks!
That should do the trick, I've added a delete button, that will slide the "deleted" doc out.
enjoy.
<template>
<v-app>
<v-expansion-panel popout>
<transition-group name="list" tag="v-expansion-panel">
<v-expansion-panel-content v-for="doc in filteredclienti" :key="doc.id">
<div slot="header">
<span>{{doc.data}}</span>
<v-btn class="error" #click="deleteItem(doc.id)">
<v-icon>delete</v-icon>
</v-btn>
</div>
<v-card>Card content</v-card>
</v-expansion-panel-content>
</transition-group>
</v-expansion-panel>
</v-app>
</template>
<script>
export default {
data: () => ({
filteredclienti: [
{ id: 1, data: "data1" },
{ id: 2, data: "data1" },
{ id: 3, data: "data1" },
{ id: 4, data: "data1" }
]
}),
methods: {
deleteItem(id) {
this.filteredclienti = this.filteredclienti.filter(d => d.id !== id);
}
}
};
</script>
<style>
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateX(100vw);
}
</style>

Vue DOM not reactive to computed property

I have a button that is set to be disabled if a computed property's valid property is false. If true, the button should be enabled and allow a user to move to the next step in the current flow.
My currentStep computed property is updating perfectly on changes to the current step's inputs, but the button :disabled="currentStep.valid" isn't recognizing the changes that ARE HAPPENING to currentStep.valid.
If I click on the current component (addnewprogram) in vue-devtools to see it's data, the button displays correctly!
Seen here: http://recordit.co/XH6HX7JLhV
However, without clicking on addnewprogram in the devtools, it doesn't function correctly.
Is there an obvservation caveat I'm missing?
The code for this functionality can be found here:
<template>
<section class="newprogram">
<div class="newprogram--content">
<div class="newprogram--stepone" v-if="progression.current === 1">
<div class="content--left">
<a class="link uppercase">use existing program information<i class="fa fa-picture-o"></i></a>
<base-input v-for="input in currentStep.inputs"
:key="input.id"
:data="input"
v-model="input.value"></base-input>
</div>
<div class="content--right">
<!-- images -->
</div>
</div>
<div class="newprogram--steptwo" v-if="progression.current === 2">
<choice-progression :step="1"></choice-progression>
</div>
</div>
</div>
<!-- Consistent among all steps -->
<div class="container--bottomnav">
<div class="bottomnav--left">
<base-btn class="button-fluid"
:data="currentStep.btns[0]"></base-btn>
</div>
<div class="bottomnav--right">
<base-btn :data="currentStep.btns[1]"
:disabled="currentStepValid"></base-btn>
</div>
</div>
<!-- -->
</section>
</template>
<script>
import bottomNav from '../main/bottom-nav.vue';
import baseProgressionBarbell from '../base/base-progression-barbell.vue';
import baseInstruction from '../base/base-instruction.vue';
import baseInput from '../base/base-input.vue';
import baseBtn from '../base/base-btn.vue';
import choiceProgression from '../secondary-flows/choice-progression.vue';
export default {
name: 'addNewProgram',
components: {
bottomNav,
baseProgressionBarbell,
baseInstruction,
baseInput,
baseBtn,
choiceProgression
},
computed: {
progression () {
return this.$store.getters.getProgression('addnewprogram');
},
steps () {
return this.$store.getters.getSteps('addnewprogram');
},
currentStep () {
return this.steps[this.progression.current - 1];
},
currentStepValid () {
return this.currentStep.valid == false ? true : false;
},
stepOneValidation () {
this.steps[0].inputs.forEach(input => {
if (!input.value) {
return this.$set(this.steps[0], 'valid', false);
}
this.$set(this.steps[0], 'valid', true);
});
},
stepTwoChoices() {
return this.$store.getters.getChoices('addnewprogram', 1);
}
}
}
</script>
<style lang="sass" scoped>
#import '../../sass/_variables.sass'
.newprogram
display: flex
flex-direction: column
.container--newprogram
display: flex
flex-direction: column
height: 100%
padding: $s1
.newprogram--header
display: flex
justify-content: space-between
align-items: center
h1
padding: 0
.newprogram--content
display: flex
// justify-content: center
// align-items: center
height: 100%
padding-top: $s2
</style>
You are updating members of a computed item. Computed items aren't editable. You need a data item, or you need to write your changes to the $store and have them refresh from there.