I am new in Vue JS. So, if anything wrong never mind.
I am using vue-bulma-tabs module for tabs component. I want to change the tabs dynamically from another component. Here, is a selected props for the currently selected tab. I want to change the selected props value by global variable so that I can show any tab from any component.Is it possible if not what is the solution? If possible, please answer me as soon as possible.
Here is my current tabs code:
<tabs>
<tab name="About Us">
<h1>This part is about us
</h1>
</tab>
<tab name="About our culture">
<h1>This part is about our culture
</h1>
</tab>
<tab name="About our vision" selected="selectedTab">
<h1>This part is about our vision
</h1>
</tab>
</tabs>
<button type="button" #click="GoTab ()">Go to tab</button>
I want when I click Go to tab button then it will go to About our vision tab.
My Vue Js code:
<script>
import TabParentComponent from
'../../components/layout/tabParentComponent.vue'
import TabChildComponent from
'../../components/layout/tabChildComponent.vue'
export default {
components: {
'tab': TabChildComponent,
'tabs': TabParentComponent
},
data () {
return {
selectedTab: false
}
},
methods: {
GoTab () {
this.selectedTab = true
}
}
}
</script>
It works when seletedTab = true in data section. But I want to when button click it will be true otherwise false.
Especially, I want to keep a vuex store data. Depending on store value selectedTab will be true or false.
look this version with vuex
seletedTab is a getters, use it anywhere in the app.
Vue Js code:
<script>
import TabParentComponent from
'../../components/layout/tabParentComponent.vue'
import TabChildComponent from
'../../components/layout/tabChildComponent.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
'tab': TabChildComponent,
'tabs': TabParentComponent
},
computed: {...mapGetters([
'selectedTab'
])
},
methods: {
...mapActions([
'GoTab'
])
}
}
</script>
Do not forget that the structure of the application with vuex will be slightly different! See Application Structure
Related
I'm using Vue 3, NaiveUI, Vitest + Vue Testing Library and got to the issue with testing component toggle on button click and conditional rendering.
Component TSample:
<template>
<n-button role="test" #click="show = !show" text size="large" type="primary">
<div data-testid="visible" v-if="show">visible</div>
<div data-testid="hidden" v-else>hidden</div>
</n-button>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { NButton } from 'naive-ui'
export default defineComponent({
name: 'TSample',
components: {
NButton
},
setup() {
const show = ref(true)
return {
show
}
}
})
</script>
The test case I have:
import { render, waitFor } from '#testing-library/vue'
import TSample from './TSample.vue'
import userEvent from '#testing-library/user-event'
describe('Tests TSample component', () => {
it('toggles between visible and hidden text inside the button', async () => {
const user = userEvent.setup()
const { getByText, queryByText, getByRole } = render(TSample)
expect(getByRole('test')).toBeInTheDocument()
expect(getByText(/visible/i)).toBeInTheDocument()
expect(queryByText('hidden')).not.toBeInTheDocument()
await user.click(getByRole('test'))
await waitFor(() => expect(queryByText(/hidden/i)).toBeInTheDocument()) <-- fails
})
})
The error:
<transition-stub />
<span
class="n-button__content"
>
<div
data-testid="visible"
>
visible
</div>
</span>
</button>
</div>
</body>
</html>...Error: expect(received).toBeInTheDocument()
received value must be an HTMLElement or an SVGElement.
Moreover in Testing Preview I get:
<button
class="n-button n-button--primary-type n-button--large-type mx-4"
tabindex="0"
type="button"
disabled="false"
role="test"
>
<transition-stub>
</transition-stub><span class="n-button__content">
<div data-testid="visible">visible</div>
</span>
</button>
a button, which makes it more confusing to me... Same situation happened when I replaced waitFor with nextTick from Vue, the component didn't do a toggle at all on click.
What works but isn't acceptable
When I changed the n-button to just button, the test passed and divs are toggled, but that's not the goal of this component. The component isn't supposed to be changed.
What I have tried:
I tried different approaches with reaching the div that contains hidden text. Either it was like above - queryByText/getByText or getByTestId, but test fails at the same point.
Also followed with similar approach shown at Testing Library - Disappearance Sample
but doesn't work in my case above.
What actually is going on and how can I test the change on click with such third-party components?
If more info is needed/something is missing, also let me know, I'll update the question.
Any suggestions, explanations - much appreciated.
Nuxt 2.15.6; I want to switch the layout of my menu component by dynamically switching menu components in my root layout.
default.vue
<template>
<component :is="navLayout"></component>
<Nuxt :navLayout="navLayout = $event" />
</template>
data() {
return {
navLayout: "default"
};
},
In the "child" components of , my pages eg. login.vue (/login) I $emit an event;
...
import nav2 from "#/layouts/nav2";
...
created() {
this.$emit("navLayout", nav2);
},
Now it seems to be the <Nuxt> component is not able to catch the event. I also tried calling a <Nuxt #navLayout="test()" /> method.
How can I avoid this.$root.$emit(...); in my login.vue and
this.$root.$on("navLayout", navLayout => {
this.navLayout = navLayout;
});
in default.vue?
EDIT: This answer works fine as it looks like you cannot do it right now: https://github.com/nuxt/nuxt.js/issues/8122#issuecomment-709443008
In the child component
<button #click="$nuxt.$emit('eventName', 'nice payload')">nice</button>
On the default layout
<script>
export default {
created() {
this.$nuxt.$on('eventName', ($event) => this.test($event))
},
methods: {
test(e) {
console.log('test ok >>', e)
},
},
}
</script>
Putting a listener on Nuxt itself does not work.
<Nuxt #navLayout="navLayout = $event" :navLayout="navLayout" />
I can see the event go and the listener plugged to <nuxt></nuxt> but it does not trigger any method with the listener...
PS: works for <nuxt-child></nuxt-child> at least.
Maybe I don't understand your question correctly, but it seems to me that you are trying to do yourself what layouts are meant to do. This would mean that you would create a layout with the menu component for login, a default layout etc. like this:
login.vue
<template>
<LoginMenu>
<Nuxt/>
</template>
default.vue
<template>
<DefaultMenu>
<Nuxt/>
</template>
On your page you would do:
export default {
layout: login
}
And then that would load the layout with the login menu component. On all other pages it would load the default menu.
More info here: https://nuxtjs.org/examples/layouts/
I am building a web app. I have few components that are modals (that show data about customers, lessons, ...).
I search a way to show one of the components easily.
And if possible doing lazy loading.
What's the best way to perform this?
Check out conditional rendering, specifically v-if. This would only load the modal if the button is clicked for example.
https://v2.vuejs.org/v2/guide/conditional.html#v-if
Single page component:
<template>
<div>
<div
v-if="showModal"
class="modal">
Stuff
</div>
<button #click="toggleModal">
Toggle Modal
</button>
</div>
</template>
<script>
export default {
data () {
return {
showModal: false
}
},
methods: {
toggleModal() {
this.showModal = !this.showModal
}
},
}
</script>
I use nuxt and I followed this guide to make custom loading component:
https://nuxtjs.org/api/configuration-loading/#use-a-custom-loading-component
This does work, but the loader is in the same position as the original nuxt loader bar:
You can see, I really added a very big and very simple loader with a red div.
At the bottom you can see my headebar (black bar with letter «s»)
so everything is moved downwards.
What I would like to achieve is that the loader takes the position of the page content instead to keep the header and the footer in place.
Right now, it all shifts down to make space for the custom loader on top.
Is there a solution for that?
Thanks in advance
Cheers
J
Well I built a big workaround:
I set a loading component in my nuxt.config:
loading: '~/components/Loading/Loading.vue',
This component should never display anything, but has these two methods:
methods: {
start () {
this.$store.commit('ui/SHOW_LOADER')
},
finish () {
this.$store.commit('ui/HIDE_LOADER')
}
}
With those I mutate the vuex ui store.
export const mutations = {
SHOW_LOADER (state) {
state.nuxtLoader = true
},
HIDE_LOADER (state) {
state.nuxtLoader = false
}
}
nuxtLoader: false, <=> nuxtLoader: true,
Within this store I set a getter:
export const getters = {
nuxtLoader: state => state.nuxtLoader
}
And on my layouts I display <nuxt /> or the CustomLoader component (which holds an animated SVG) depending on the ui store nuxtLoader property.
<template>
<div>
<HeaderBar />
<main id="main" class="Layout__content">
<CustomLoader v-if="nuxtLoader" />
<nuxt v-else />
</main>
<Footer />
</div>
</template>
Now I give the user a feedback with a custom loader placed between headerbar and footer. 💪
I am still open for less work-aroundy and slicker solutions.
Cheers
J
I'm using Vue Onsen UI and trying to render a Vue single file component for each tab.
In the documentation here, they make use of template in a single page. Which is not very reusable. I want to be able to import custom component and render that.
Here is something that I'm trying to do which doesn't seem to work.
<template lang="html">
<v-ons-page>
<!-- top tab bar -->
<v-ons-tabbar position="top" :index="0">
<v-ons-tab label="Browse" page="TaskList">
</v-ons-tab>
<v-ons-tab label="Second">
</v-ons-tab>
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
export default {
template: '#main',
components: {
'task-list': TaskList,
},
};
</script>
<style lang="scss">
</style>
Can you suggest anything that I should try?
Instead of using tab objects that reference the components directly, use the :tabs property of the tabbar to set up the pages:
<template lang="html">
<v-ons-page>
<v-ons-tabbar position="top" :index="0" :tabs="tabs">
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
import SecondPage from './SecondPage';
export default {
template: '#main',
data: function () {
return {
tabs: [
{label: 'Browse', page: TaskList},
{label: 'Second', page: SecondPage}
]
}
}
};
</script>
Also, make sure the root element of the components you reference in the page property are <v-ons-page> elements.
I was having the same difficulty with the following syptoms:
Tabs were not appearing at all
No errors in CLI or in console
Note that I was also using the "Hello World" app that is generated from the CLI (vue init OnsenUI/vue-pwa-webpack hello-world)
Resolution
It was pretty simple in the end: there is a file in the root of the folder called vue-onsen-components.js which has all of the components and some of them are commented out. I had to uncomment the following lines and then the tabs appeared:
export { default as VOnsTab } from 'vue-onsenui/esm/components/VOnsTab'
export { default as VOnsTabbar } from 'vue-onsenui/esm/components/VOnsTabbar'