We have Vue.js app that uses Quasar component framework.
The screen shots look as following:
Incorrect case:
Correct case:
I need the only one toggle button group should be active, either percents or standard amounts. Pay attention there’s an array of toggle button groups.
The code I wrote produces the incorrect case. It looks as following:
JavaScript
x
148
148
1
<template>
2
<q-dialog v-model="show" no-backdrop-dismiss full-width>
3
<q-card>
4
<q-card-section class="row items-center">
5
<div class="text-h6 tip-color">Tip</div>
6
<q-space />
7
<q-btn icon="close" flat round dense v-close-popup @click="cancel" />
8
</q-card-section>
9
<q-card-section style="max-height: 50vh" class="scroll set-border">
10
<div class="q-gutter-md">
11
<q-card v-for="({ master }, index) in items" :key="master.id">
12
<div class="row">
13
<div class="col-3 flex justify-center items-center">
14
<Avatar
15
:src="master.employer_avatar"
16
:size="50"
17
no-default-spinner
18
/>
19
<span class="q-ml-md text-caption text-secondary">
20
{{ getEmployerName(master) }}
21
</span>
22
</div>
23
<div class="col">
24
<q-card-section>
25
<q-btn-toggle
26
v-model="togglePercentPayments[index]"
27
toggle-color="primary"
28
:options="percentPayments"
29
spread
30
@input="getFullTip"
31
/>
32
</q-card-section>
33
<q-card-section>
34
<q-btn-toggle
35
v-model="toggleStandardPayments[index]"
36
toggle-color="primary"
37
:options="standardPayments"
38
spread
39
@input="getFullTip"
40
/>
41
</q-card-section>
42
</div>
43
</div>
44
</q-card>
45
</div>
46
</q-card-section>
47
<q-card-section>
48
<div><strong>Summary:</strong> {{ total }}</div>
49
<div>
50
<strong>Tip:</strong> {{ getFullTip() ? getFullTip() : 0 }}
51
</div>
52
</q-card-section>
53
<q-card-actions align="right" class="text-primary q-pt-none">
54
<q-btn flat label="Cancel" @click="cancel" />
55
<q-btn flat label="Pay" @click="pay" />
56
</q-card-actions>
57
</q-card>
58
</q-dialog>
59
</template>
60
61
<script>
62
const percentPayments = [
63
{ label: '5%', value: 5 },
64
{ label: '10%', value: 10 },
65
{ label: '15%', value: 15 },
66
]
67
68
const standardPayments = [
69
{ label: '100', value: 100 },
70
{ label: '200', value: 200 },
71
{ label: '500', value: 500 },
72
]
73
74
export default {
75
props: {
76
showModal: {
77
type: Boolean,
78
default: false,
79
},
80
items: {
81
type: Array,
82
default: () => [],
83
},
84
total: {
85
type: Number,
86
default: 0,
87
},
88
},
89
data: function() {
90
return {
91
show: false,
92
togglePercentPayments: new Array(this.items.length).fill(null),
93
toggleStandardPayments: new Array(this.items.length).fill(null),
94
percentPayments,
95
standardPayments,
96
}
97
},
98
watch: {
99
showModal(newVal) {
100
this.show = newVal
101
},
102
},
103
methods: {
104
getEmployerName(master) {
105
return `${master?.first_name ?? ''} ${master?.last_name[0] ?? ''}.`
106
},
107
getPercentage(total, percent) {
108
return (total / 100) * percent
109
},
110
getFullTip() {
111
let standardSum = 0
112
for (const standardPayment of this.toggleStandardPayments) {
113
standardSum += standardPayment
114
}
115
116
let percentageSum = 0
117
for (const percentagePayment of this.togglePercentPayments) {
118
const percent = this.getPercentage(this.total, percentagePayment)
119
percentageSum += percent
120
}
121
122
return standardSum + percentageSum
123
},
124
pay() {
125
this.$emit('pay', this.getFullTip())
126
this.clear()
127
},
128
cancel() {
129
this.$emit('cancel')
130
this.clear()
131
},
132
clear() {
133
this.togglePercentPayments = new Array(this.items.length).fill(null)
134
this.toggleStandardPayments = new Array(this.items.length).fill(null)
135
},
136
},
137
}
138
</script>
139
140
<style scoped>
141
.set-border {
142
border: 1px solid gainsboro;
143
}
144
.tip-color {
145
color: rgb(4, 171, 171);
146
}
147
</style>
148
How to make 2 Quasar toggle button groups mutually exclusive?
Advertisement
Answer
Here’s the solution if anyone needs. The guys from Quasar tech support helped me.
JavaScript
1
161
161
1
<template>
2
<q-dialog v-model="show" no-backdrop-dismiss full-width>
3
<q-card>
4
<q-card-section class="row items-center">
5
<div class="text-h6 tip-color">Tip</div>
6
<q-space />
7
<q-btn icon="close" flat round dense v-close-popup @click="cancel" />
8
</q-card-section>
9
<q-card-section style="max-height: 50vh" class="scroll set-border">
10
<div class="q-gutter-md">
11
<q-card v-for="({ master }, index) in items" :key="master.id">
12
<div class="row">
13
<div class="col-3 flex justify-center items-center">
14
<Avatar
15
:src="master.employer_avatar"
16
:size="50"
17
no-default-spinner
18
/>
19
<span class="q-ml-md text-caption text-secondary">
20
{{ getEmployerName(master) }}
21
</span>
22
</div>
23
<div class="col">
24
<q-card-section>
25
<q-btn-toggle
26
v-model="togglePayments[index]"
27
toggle-color="primary"
28
:options="percentPayments"
29
spread
30
@input="getTotalTip"
31
/>
32
</q-card-section>
33
<q-card-section>
34
<q-btn-toggle
35
v-model="togglePayments[index]"
36
toggle-color="primary"
37
:options="standardPayments"
38
spread
39
@input="getTotalTip"
40
/>
41
</q-card-section>
42
</div>
43
</div>
44
</q-card>
45
</div>
46
</q-card-section>
47
<q-card-section>
48
<div><strong>Summary:</strong> {{ total }}</div>
49
<div>
50
<strong>Tip:</strong> {{ getTotalTip() ? getTotalTip() : 0 }}
51
</div>
52
</q-card-section>
53
<q-card-actions align="right" class="text-primary q-pt-none">
54
<q-btn flat label="Cancel" @click="cancel" />
55
<q-btn flat label="Pay" @click="pay" />
56
</q-card-actions>
57
</q-card>
58
</q-dialog>
59
</template>
60
61
<script>
62
import { axiosInstance } from 'src/boot/axios'
63
import { api } from 'src/api'
64
65
const percentPayments = [
66
{ label: '5%', value: 0.05 },
67
{ label: '10%', value: 0.1 },
68
{ label: '15%', value: 0.2 },
69
]
70
71
const standardPayments = [
72
{ label: '100', value: 100 },
73
{ label: '200', value: 200 },
74
{ label: '500', value: 500 },
75
]
76
77
export default {
78
props: {
79
showModal: {
80
type: Boolean,
81
default: false,
82
},
83
items: {
84
type: Array,
85
default: () => [],
86
},
87
total: {
88
type: Number,
89
default: 0,
90
},
91
orderId: {
92
type: Number,
93
required: true,
94
},
95
},
96
data: function() {
97
return {
98
show: false,
99
togglePayments: new Array(this.items.length).fill(0.0),
100
percentPayments,
101
standardPayments,
102
}
103
},
104
watch: {
105
showModal(newVal) {
106
this.show = newVal
107
},
108
},
109
methods: {
110
getEmployerName(master) {
111
return `${master?.first_name ?? ''} ${master?.last_name[0] ?? ''}.`
112
},
113
getValue(value, amount) {
114
const floatValue = Number.parseFloat(value)
115
if (floatValue > 1) {
116
return floatValue
117
}
118
return floatValue * amount
119
},
120
getTotalTip() {
121
let totalTip = 0
122
for (const tip of this.togglePayments) {
123
totalTip += this.getValue(tip, this.total)
124
}
125
126
return totalTip
127
},
128
async pay() {
129
try {
130
const response = await axiosInstance.post(api.payments.all, {
131
reason_type: 'order',
132
reason_id: this.orderId,
133
amount: this.total + this.getTotalTip(),
134
})
135
this.$store.commit('booking/setCreatedPayment', response.data.data)
136
this.$router.push({ name: 'Payment' })
137
} catch (e) {
138
console.info(e)
139
}
140
},
141
cancel() {
142
this.$emit('cancel')
143
this.clear()
144
},
145
clear() {
146
this.togglePercentPayments = new Array(this.items.length).fill(0.0)
147
this.toggleStandardPayments = new Array(this.items.length).fill(0.0)
148
},
149
},
150
}
151
</script>
152
153
<style scoped>
154
.set-border {
155
border: 1px solid gainsboro;
156
}
157
.tip-color {
158
color: rgb(4, 171, 171);
159
}
160
</style>
161