Vuetify tabs won't change when changing v-model - vue.js

I am currently trying to make the active tab change when I put a value in a variable which controls the component, but it doesn't work. I am binding a variable to v-model and then changing that variable with the value I want. The point is, wheter the value is a number or a string, it doesn't matter because the tabs won't work.
<v-card flat>
<v-tabs v-model="tab" fixed-tabs>
<v-tab v-for="(instance, idx) in tabData" :key="`${idx}`" #click="callChildrenToUpdate(idx)">
<v-badge color="red" size="18" class="p-2" v-if="instance"></v-badge>
...
</v-tab>
</v-tabs>
...
</v-card>
The data:
data () {
return {
tab: null,
items: [],
tabData: this.tabsData
}
},
And then in the mounted hook I try changing it, but it won't work.
this.tab = 87

On this situation, do NOT use template strings when setting the tab key.
So to make it work, change this:
<v-tab v-for="(instance, idx) in tabData" :key="`${idx}`" #click="callChildrenToUpdate(idx)">
To:
<v-tab v-for="(instance, idx) in tabData" :key="idx" #click="callChildrenToUpdate(idx)">
Now when you do:
this.tab = 87
You should get your tabs to go to index 87 (which seems a lot).
If this is actually an ID, you could do a logic like:
this.tab = this.tabData.findIndex(i => i.id === 87)

Related

Passing props into component which has v-if set

I have a page with a stepper. I conditionally display a step, based on what step user is on. When flicks between steps (user can go back and forth) I noticed that my props are no longer passed over. What can be done about it?
View page:
<v-container v-if="stepNumber === 1">
<sectionOne :restrictions="restrictions" />
</v-container>
<v-container v-if="stepNumber === 2">
<sectionTwo :restrictions="restrictions" />
</v-container>
Within a section component:
#Prop() readonly restrictions: RestrictionsDomain = new RestrictionsDomain([]);
I understand that I can avoid a need for passing a prop with help of vuex, but I am wondering if anything can be done to get my props to work as is? Also, I can't use v-show for this either.
Since v-if destroys the element, thus removing the props' reactivity, and if you can't use v-show, I'd consider using a watcher on the prop and setting another reactive variable that'd trigger the visibility of that element.
So you'd get something like this:
<v-container v-if="step === 1">
<sectionOne :restrictions="restrictions" />
</v-container>
<v-container v-if="step === 2">
<sectionTwo :restrictions="restrictions" />
</v-container>
props: ['stepNumber'],
data() {
return {
step: 1,
}
},
watch: {
stepNumber(newVal) {
this.step = newVal
}
}

How to change the behavior of clicking an option item of v-autocomplete

Scenario
When clicking an option item, natively, the v-autocomplete (with multiple prop) active its respective checkbox and keeps with the menu open, allowing you to continue selecting other items until you click out of the menu
Objective
What I would like is to change this behavior, when I clicked only in the checkbox, the native behavior is maintained, but when clicked specifically on the line, the menu is closed and trigger a function using the value of the selected item.
I imagine that it is necessary to use the slots but I really don't know how to use it or if this is the best way to obtain this new behavior.
Note
The vertical line is for concept demonstration purposes only, it is not necessary to include this line in the component.
As you said, you can do it using slots. The idea is to override items display to remove the clickable v-list-item underneath. The drawback is that you have to re-implement values selection.
You'll need a checkbox and two methods: isSelected and toggleItem.
Template section:
<v-autocomplete
v-model="values"
:items="items"
outlined
dense
chips
small-chips
label="Outlined"
multiple
>
<template #item="{ item }">
<v-list-item class="d-flex">
<div>
<v-simple-checkbox color="primary" :value="isSelected(item)" #click="toggleItem(item)" />
</div>
<div class="ml-2">{{ item }}</div>
</v-list-item>
</template>
</v-autocomplete>
Script section:
data: () => ({
items: ['foo', 'bar', 'fizz', 'buzz'],
values: ['foo', 'bar'],
}),
methods: {
isSelected(item) {
return this.values.includes(item);
},
toggleItem(item) {
if (this.values.includes(item)) {
this.values = this.values.filter(v => v !== item);
} else {
this.values.push(item);
}
}
}
Please take a look at this working example.

Access to a slot function inside a child component in VusJS

I'm trying to use tiptap. Actually it works, but what I'm trying to do is to access the "isActive" slot from outside the editor component, and I don't know how to do it.
Here is a codesandbox example: https://codesandbox.io/s/v07xnxo807?file=/src/App.vue
You see the Editor component is called from the App.vue. The buttons in the Editor component are activated depending on the "isActive" slot functions.
What I would like is to access this slot to get for example the value of isActive.bold() from the App.vue, in order to update the model of a "multiple button" you can find on Vuetify: https://vuetifyjs.com/fr-FR/components/button-groups/
Here is for example what I could have:
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
<v-btn-toggle
v-model="toggle_multiple"
dense
background-color="primary"
dark
multiple
class="my-2"
>
<v-btn :color="isActive.bold()?'red':'green'" #click="commands.bold">
<v-icon>mdi-format-bold</v-icon>
</v-btn>
<v-btn #click="commands.italic">
<v-icon>mdi-format-italic</v-icon>
</v-btn>
<v-btn #click="commands.strike">
<v-icon>mdi-format-strikethrough</v-icon>
</v-btn>
<v-btn #click="commands.underline">
<v-icon>mdi-format-underline</v-icon>
</v-btn>
<v-btn #click="commands.blockquote">
<v-icon>mdi-format-quote-open</v-icon>
</v-btn>
</v-btn-toggle>
</editor-menu-bar>
And the toggle_multiple would be computed depending on the different "isActive" function values.
I already tried:
computed: {
toggle_multiple: function () {
let t = []
if (editor) {console.log("Bold: "+editor.isActive.bold())}
return t
}
},
But I receive this error: error 'editor' is not defined
I'm open to any suggestion.
Thanks in advance.
Property isActive is stored in the tiptap instance (in your case it's this.editor):
In HTML:
<div>{{editor.isActive.bold()}}</div>
In JS:
<div>{{toggle_multiple}}</div>
computed: {
toggle_multiple () {
// Keep in mind, other properties like ".isActive.heading()" will be undefined
// until you import the extension for it.
// So the function "heading" below exists only if you're using that extension
// console.log(this.editor.isActive.heading({ level: 2 })
return this.editor.isActive.bold()
}
}

How can I add search country code on vue tel input?

My vue component :
<v-container>
<v-row>
<v-col cols="12" sm="6" md="3">
<vue-tel-input v-model="phone" v-on:country-changed="countryChanged"></vue-tel-input>
</v-col>
</v-row>
</v-container>
<v-btn
color="success"
#click="submit"
>
submit
</v-btn>
My codepen : https://codepen.io/positivethinking639/pen/XWWBXMW?editors=1011
I want display search like this :
So make it easier for users to choose the country code
How can I do it?
I think the simplest is to have two drop-downs side-by-side, so it looks just like the one you posted. When the user clicks "Save", have the v-model with the country code and the v-model with the number joined.
data () => ({
countryCode: '+81',
number: '555-5555'
}),
methods: {
submitForm () {
const phone = countryCode + number //or however you want to concatenate
//do other stuff here
}
}
Your other options are to splice and add the country code to the string ahead of the phone number on change, but that seems a little overkill for something with a simple solution.
If I'm not understanding your question, please add a little more detail.
If you specifically want the numbers to show, then you'll have to make changes to the library options you're using. It seems you're using vue-tel-input package, right?
You can set the + code to show with this:
inputOptions: {
showDialCode: true
}
Check out all the options here:
https://www.npmjs.com/package/vue-tel-input

Switch Vuetify navigation drawer to mini and then temporary

I have a project in Vue.js and I am using Vuetify. I have a toolbar and navigation drawer. What I would like is when on desktop the drawer is open. If the user clicks the side-icon the drawer switches to mini.
If on md the drawer switches to mini. if the user clicks the side-icon the mini switches back to drawer
If on sm or lower the navigation drawer switches to temporary
I have most of the pieces but I am getting an error when I click the side-icon. Computed property 'mini' was assigned to but it has no setter.
Here is my code:
<v-toolbar
:clipped-left="$vuetify.breakpoint.mdAndUp"
:app="$vuetify.breakpoint.mdAndUp"
:fixed="$vuetify.breakpoint.mdAndUp"
flat
fixed
:scroll-toolbar-off-screen="$vuetify.breakpoint.smAndDown"
:scroll-threshold="50">
<v-toolbar-side-icon #click.stop="mini = !mini">
</v-toolbar-side-icon>
<v-toolbar-title class="text-uppercase">
<span class="font-weight-light">LOGO</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items class="">
<v-btn icon v-for="item in menu" :key="item.icon">
<v-icon>{{item.icon}}</v-icon>
</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-navigation-drawer
clipped
:mini-variant="mini"
v-model="drawer"
:permanent="$vuetify.breakpoint.mdOnly"
:temporary="$vuetify.breakpoint.smAndDown"
app
hide-overlay>
<v-list dense>
<v-list-tile
v-for="(item, index) in items"
:key="index"
>
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
I have created a codepen with what I have so far:
https://codepen.io/jsd219/pen/gJJMPQ
You're trying to assign a computed property to itself:
#click.stop="mini != mini"
You really don't want to do that. To find out why, you want to read on JS setters and getters.
If you want mini to be the computed which determines if your <navigation-drawer> is minified or not, use two separate placeholders for your info:
one for whether the menu is forcefully opened (call it menuOpen), initially defined in data(), as false and then overwritten by your #click.stop="menuOpen != menuOpen"
and one coming from $vuetify.breakpoint.mdAndUp. Call it mdAndUp.
So your mini becomes:
mini() {
return !(this.mdAndUp|| this.menuOpen);
}
See it here.
The problem is that you are trying to modify the computed property mini.
To mutate a computed property, you would need to provide a computed setter:
computed: {
mini: {
get() {
// get logic
},
set(value) {
// set logic
}
}
}
In your case, your computed property mini returns true or false if based on $vuetify.breakpoint.mdAndDown. You would need to include a new variable, something like overwriteBreakpoint and use that in your setter.
data() => ({
overwriteBreakpoint: true
}),
computed: {
mini: {
get() {
return this.$vuetify.breakpoint.mdAndDown || this.overwriteBreakpoint;
},
set(value) {
this.overwriteBreakpoint = value;
}
}
}
Here's an example: https://codepen.io/dormenog/pen/MddbMY?editors=1011
Update:
To make this work on multiple screen sizes you'll need to come up with defined rules on when each prop of your nav bar should be true or false. This will become very messy, very quickly, and the benefit of the keeping track of the state is not really valuable because the screens will not change size in real time on the user's device.
I would advice separating the contents of your navbar into a component and wrap it with multiple <v-navigation-drawer /> that will only be rendered by vue if the screen size is correct. This can be achieved using v-if and v-else.