I've been trying to solve this mystery for a week now.
I'm trying to set up a sidebar with Vuetify in my Nuxt/Vue website where people click on the hamburger menu and the sidebar opens up. To do this I set up the hamburger menu to run a toggle method.
<v-app-bar-nav-icon #click="toggleSidebar"></v-app-bar-nav-icon>
......
<script>
import { mapMutations } from 'vuex';
export default {
methods: {
...mapMutations({
toggleSidebar: 'appSidebar/toggleSidebar'
})
}
}
</script>
The method then update vuex state
export const state = () => ({
sidebarOpen: false
})
export const mutations = {
toggleSidebar(state) {
state.sidebarOpen = !state.sidebarOpen;
},
}
This works fine. The bar opens and close when I click on the hamburger menu. However, for some reason, which I'm glad it does, the sidebar closes when I click outside the sidebar (if anyone could explain how this works too i'd be appreciated). When this happens, the state doesn't update and the next time i want to open i need to click on the menu twice to get it back to close then open again.
This is how i set up the sidebar
<v-app>
<v-navigation-drawer app temporary clipped v-model="status" color="blue lighten-3" dark>
<script>
export default {
computed: {
status (){
return this.$store.state.appSidebar.sidebarOpen
}
}
}
</script>
Thank you for your help!
The drawer closes when you click outside because of the temporary prop. According to your code, your state changes only on clicking the hamburger button. But internally vuetify uses the temporary property. You can either do without your vuex code or without the temporary prop.
Related
I have created a ionic vue 3 tabs starter application.
Im trying to to switch tab programmatically from one tab to another
here is my situation
// in Tab1.vue page
setup(props, context) {
function moveToTab3(){
// here I need the code to switch tab1 to tab3
// possible to call tabs.select() method here ?
}
}
// my Tabs.vue page
<ion-tabs ref="tabs" >
I searched in the ionic docs and vue docs to know how to get the parent component from a child component, I have not got a solution yet.
any help is much appreciated, Thank you so much
yes you can absolutely do that programmatic routing provided you have access to Vue-Router because ionic under the hood uses Vue router for navigation and since tabs are top-level navigation you can simply call
$router.push OR $router.replace inside of your setup function on button click or bind the tab using router-link
Here is the documentation from Ionic related to Navigation/Routing Link And
I think this is what you are looking for Accessing The Ionrouter Instance Link
=====Update =====
Taken directly from the documentation Link, As you can see in the template on Ion-Button a simple #click is used to push the route you wish to navigate, while in script tag useRouteris accessed from the core vue-router to get access to the underlying router
<template>
<ion-page>
<ion-content>
<ion-button #click="() => router.push('/detail')">Go to detail</ion-button>
</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonButton, IonContent, IonPage } from '#ionic/vue';
import { defineComponent } from 'vue';
import { useRouter } from 'vue-router';
export default defineComponent({
name: 'HomePage',
components: {
IonButton,
IonContent,
IonPage
},
setup() {
const router = useRouter();
return { router };
}
})
</script>
The same link also shows how you use router-link on Ion-Button
<ion-button router-link="/detail">Go to detail</ion-button>
without having to tap into a method.. either way, works...
this question my look silly but i got stuck in this!
i'm using Vuetify skeleton and created a data isLoading like the codes bellow. on page refresh every thing is fine but on route change (go back and forward in my pages) it's not working.
in my codes, when page is refreshed btn becomes disabled and mycomponent show skeleton using the same isLoading in its file. but when i go forward and back to it, my btn is loaded, not disabled, mycomponent load after a time without showing skeleton!
what's the problem! i guest it's about using the lifecycle!
<template>
<div>
<v-btn :disabled="isLoading">Button</v-btn>
<mycomponent />
</div>
</template>
<script>
import mycomponent from '~/components/mycomponent'
export default {
components:{
'mycomponent': mycomponent
},
data(){
return{
isLoading: true
}
},
created(){
this.isLoading = true
},
mounted(){
this.isLoading = false
}
}
</script>
mycomponent:
<template>
<v-skeleton-loader
:loading="isLoading"
type="button"
width="100%"
>
<v-btn>Button</v-btn>
</v-skeleton-loader>
</template>
<script>
export default {
data(){
return{
isLoading: true
}
},
created(){
this.isLoading = true
},
mounted(){
this.isLoading = false
}
}
</script>
So The Problem: It only works when i land on page for first time or refresh browser. by going forward and back to this page neither disable button nor skeleton on component works.
Update
I'm on NuxtJs v2.13
The created hook is called when the vue instance is created and the mounted hook is called when the vue instance has been mounted in the DOM. These hooks are called when a component is routed to for the first time or when the page is refreshed. That explains why it only works when you land on the page for the first time or refresh the browser.
When a component has been mounted, pressing the back button on the browser won't call the created and mounted hook.
To solve your problem, you can watch the $route object, by doing
App.vue
watch: {
'$route' () {
// this will be called any time the route changes
this.isLoading = true // you can think of a way to make isLoading false
}
},
For more on lifecycle hooks, check out this article.
I created a vue dialog app/component using vue cli. It consist of a sample button to be clicked on to imitate how the dialog (What I need) will be loaded when a link on the existing application is clicked. I have a couple of issues.
When using v-app it adds the application wrapper I dont need seeing as its only the dialog I want. It creates a huge whitespace not needed. If I remove it, it errors [Vuetify] Unable to locate target [data-app] and the dialog wont load when <div #click='getInformation('USA')'></div> in the existing application is used.
Tried removing v-app and just using template but continues to error. Seems I need to still specify v-app in some way. Lost here
An example on how Im trying to pull it off but not working in App.vue
<template>
<div v-resize="onResize">
<v-dialog>
<v-card>
{{ information }}
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
data() {
return {
isMobile: false,
information: []
};
},
methods: {
onResize() {
if (window.innerWidth < 425) this.isMobile = true;
else this.isMobile = false;
},
getInformatiom(country) {
axios
.get(`${api}/${country}/info`, {
headers: {
Authorization: `token`
}
})
.then(response => {
this.information = response.data.info;
});
}
}
};
main.js
import Vue from "vue";
import App from "./App.vue";
import Vuetify from "vuetify";
import "vuetify/dist/vuetify.min.css";
Vue.use(Vuetify);
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
Dialog component is ready to go, just having so much trouble getting it to show when its being called from the existing application. Just a note, the existing application does not use Vue, its only classic asp, Im only updating the dialog on the page to look/work better using vue/vuetify. Any help would be GREATLY APPRECIATED
You NEED the v-app element with vuetify.
Try this to only use the app when showing the dialog. Then use CSS to customise the v-app.
<v-app v-if='this.information && this.information.length'>
<v-dialog>...</v-dialog>
</v-app>
I would use the max-width prop of v-dialog, make it dynamic by adding :max-width and then have that bound to a computed property which subscribes to your screen size. I would not try to control it from an external div. See here for full list of sizing options
https://vuetifyjs.com/en/components/dialogs
I'm using Vuetify to create a couple of components in a dashboard (example code).
As you can see, I have a toolbar component:
Vue.component('toolbar', {
template: '
<v-toolbar>
<v-toolbar-side-icon #click="$emit('toggle')"></v-toolbar-side-icon>
<v-toolbar-title>Application</v-toolbar-title>
</v-toolbar>'
});
I want to be able to click this toolbar to close the drawer component, so I emit an event for it: #click="$emit('toggle')"
Then, the drawer component listens with #toggle for that event to swap the boolean value of the v-model=drawer:
Vue.component('drawer', {
template: '
<v-navigation-drawer v-model="drawer" #toggle="drawer=!drawer" app>
...
</v-navigation-drawer>',
data() {
return { drawer: true }
}
});
However, clicking on toggle doesn't change value of the v-model. In order for the Vuetify component to work I need to be able to change the v-model value, I don't think I can make it work with computed properties, so I guess this rules out using Vuex.
What would be the simplest way to handle the communication between these components?
There are couple of changes that needs to be done:
add the property drawer: true on the root instance where the drawer component is rendered as pass it as props to the drawer component
new Vue({
el: '#app',
data: {
drawer: true
}
})
template
<drawer :drawer="drawer"></drawer> // pass drawer as props
Receive the drawer prop in the drawer component and set it to the v-model of <v-navigation-drawer>
Vue.component('drawer', {
template: `
<v-navigation-drawer clipped fixed app v-model="drawer">
...
</v-navigation-drawer>`,
props: {
drawer: Boolean,
source: String
}
});
you are emitting an event from the toolbar component. So you should add the event listener on the toolbar component , not the drawer component.
<toolbar #toggle="drawer = !drawer"></toolbar>
Here is the updated codepen: https://codepen.io/anon/pen/aYVYzQ?editors=1010#anon-login
My vue component like this :
<template>
<span class="rating">
...
</span>
</template>
<script>
export default {
props: {
'star': null
},
...
}
</script>
If the component is running I want to disable button back in the browser. So the user can not go back to the previous page
How can I do it?
Try this script, by adding in your html file, where you creat vue instance
history.pushState(null, null, location.href);
window.onpopstate = function () {
history.go(1);
};
Run this code whenever url changes. It will counteract user's back action
window.history.forward(1)