Ionic Vue 3 application switch tab from another tab - vue.js

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...

Related

Vue 3 Understanding examples from setup function and applying them in Setup tag

I am new to vue but scince i am fresh starting i decied to go straight up to TS and Setup tag because seems like the newest and best way to write vue js components.
Anyways i am now looking at this framework and more specific i'm into this example:
import { IonPage, onIonViewWillEnter, onIonViewDidEnter, onIonViewWillLeave, onIonViewDidLeave } from '#ionic/vue';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Home',
components: {
IonPage,
},
setup() {
onIonViewDidEnter(() => {
console.log('Home page did enter');
});
... the other hooks ...
},
});
And my question come from this block:
name: 'Home',
components: {
IonPage,
},
since i only worked with options api and setup tag i an not sure What does it imply to put an object in the components object and how could i acomplish the same objective with setup tag.
My objective is to make sure i am doing what this Note in the guide warns me about:
Note Pages in your app need to be using the IonPage component in order
for lifecycle methods and hooks to fire properly.
In <script setup> syntax, Home.vue would look like this:
<script setup lang="ts">
import { IonPage, onIonViewDidEnter, ...other hooks used here... } from '#ionic/vue';
onIonViewDidEnter(() => {
console.log('Home page did enter');
});
...other hooks used here...
</script>
The note you quoted draws attention to the template of any page/view contents needing to be wrapped in a <ion-page></ion-page> wrapper for the layout to function as intended, like in their examples.
Generic example:
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Some title</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
some content...
</ion-content>
</ion-page>
</template>
For the above layout, you'd need to import all used components:
import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '#ionic/vue'
With <script setup> you don't need to declare them as local components, <script setup> detects them and does it for you, behind the scenes. They're available for usage inside the <template> once imported.
The component name is also inferred by <script setup> from the name of the file. In the above case, it would be Home.
To sum up: behind the scenes, <script setup> takes its contents and wraps it in a
export default defineComponent({
name: // infer from file name,
components: {
// list all imported vue components
},
setup() {
// actual contents of `<script setup>`
}
})
For this to be possible, some helpers were added (defineEmits, defineProps), which allow declaring those parts of Options API inside the setup() function.
Most notably, in this syntax setup() no longer needs a return value. All variables declared or imported inside it are made available to <template>.
Important: <script setup> is a useful tool, designed to reduce boilerplate in the majority of cases, not to replace defineComponent() completely. Read more about it in the docs.

Call app.use for plugin in the component itself in vue 3

I'm building a component library that uses the v-tooltip plugin. So I need to install and use the plugin in the component itself instead using it globally with app.use().
I've read so many posts, and what I've tried so far doesn't work for my case.
I know that I can access the app in the Composition API as:
import VTooltip from 'v-tooltip';
import 'v-tooltip/dist/v-tooltip.css';
const App = getCurrentInstance().appContext.app;
App.use(VTooltip);
but that doesn't work, and I get this warning:
[Vue warn]: Component is missing template or render function.
Any help would be greatly appreciated.
to use this plugin in the component itself, you can try to do something like this:
<template>
<button v-tooltip="/* your code */"> Custom button </button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import VTooltip from "v-tooltip";
export default defineComponent({
directives: {
tooltip: VTooltip.VTooltip,
"close-popover": VTooltip.VClosePopover,
"v-popover": VTooltip.VPopover,
},
});
</script>
Thanks #Rago, you gave me an idea with the directives. The solution was really simple in this case... At the moment v-tooltip is undergoing a package rename (to floating-vue), so with the new plugin you can decide if you want to use a component or a directive.
This is the solution:
<template>
...
<span v-tooltip="help" class="form-help">?</span>
...
</template>
<script>
import 'floating-vue/dist/style.css';
import { VTooltip } from 'floating-vue';
export default defineComponent({
directives: {
tooltip: VTooltip,
},
...
});
</script>
And for the Composition API you just import it, and Vue will automatically detect the directive if you follow the naming convention - putting v in front of the directive:
import 'floating-vue/dist/style.css';
import { VTooltip } from 'floating-vue';
const vTooltip = VTooltip;

How can I wrap a vue component during cypress component testing?

I am using component testing in Cypress on Vue. My project components use the vuetify plugin.
Currently, tested components load with Vuetify:
import DebuggingTemporaryComponent from "./DebuggingTemporaryComponent";
import {mount} from "#cypress/vue";
import vuetify from '../../resources/js/vuetify'
it('mounts the component with vuetify', () => {
mount(DebuggingTemporaryComponent,{vuetify,})
cy.contains('Hello World') ✅
}
However, the stylings are not functioning correctly because Vuetify components need to be wrapped in a <v-app> at least once on the page. In component testing this is not happening.
I need to customise the wrapper as suggested here in the docs for the React equivalent. However whenever I try to make my own function to do this, I get an error that the appropriate webpack loader isn't there. Vue loader is there and working.
import {mount as cypressMount} from '#cypress/vue'
export function mount (component){
return cypressMount(<v-app>component</v-app>, prepareComponent(props, options))
}
Can anyone help me with where to go next with this?
You can construct a simple wrapper in the test, for example
Component to test - Button.vue
<template>
<v-btn color="red lighten-2" dark>
Click Me
</v-btn>
</template>
Test
import Button from "./Button";
import {mount} from "#cypress/vue";
import vuetify from '../plugins/vuetify'
import { VApp } from 'vuetify/lib/components'
const WrapperComp = {
template: `
<v-app>
<Button />
</v-app>
`,
components: {
VApp,
Button
}
}
it('mounts the component with vuetify', () => {
mount(WrapperComp, { vuetify })
const lightRed = 'rgb(229, 115, 115)'
cy.contains('button', 'Click Me') // ✅
.should('have.css', 'background-color', lightRed) // fails if no <v-app> used above
})
You get an error because you are trying to use JSX which is indeed possible with Vue but you need to configure additional build plugins.
Same can be achieved without JSX by using render function
import {mount} from "#cypress/vue";
import vuetify from '../../resources/js/vuetify'
import { VApp } from 'vuetify/lib/components'
function mountComponentWithVuetify(componentToMount, options = {})
{
return mount({
render(h) {
return h(VApp, [h(componentToMount)])
}
},
{
vuetify,
...options,
})
}

Docs for antd nuxtjs when using babel-plugin-import

I am setting up the first app using Nuxtjs and Antd. I am using babel-plugin-import to reduce bundle size of Antd.
It works fine but in the component, it seem strange.
with babel-plugin-import
<template>
<Button type="primary">Enjoy it</Button>
</template>
<script>
import { Button } from 'ant-design-vue'
export default {
components: {
Button
}
}
</script>
On the official docs, they are using different tags.
<a-button type="primary">Primary</a-button>
This is the docs from Ant Design of Vue.
How can I find the docs when using with babel-plugin-import. I already search many times on the internet. But I am not finding any results.
the elegant way:
components: {
[Button.name]: Button
}
I just found the solution.
<script>
import Button from 'ant-design-vue/lib/button';
export default {
components: {
'a-button':Button
}
}
</script>
In this thread: Import UI library modularized in nuxtjs

How to enable disable component in a complex vue app?

I am just new to vue and working on this example Notes application, it can be found below
https://coligo.io/learn-vuex-by-building-notes-app/
My question is how can I change component seen on screen right behind the toolbar. I have read basic guide but I am still behind it.
Lets say I have a button on left side call it message and have another component listing like NotesList and its called MessagesList. So, When I click message button, I want NotesList dissappear and MessageList come instead of that, and vice versa. I do not want NotesList stay as consistent on screen.
Here is App.vue and main.js files, please look in github page for mode code.
https://github.com/coligo-io/notes-app-vuejs-vuex
<template>
<div id="app">
<toolbar></toolbar>
<notes-list></notes-list>
<editor></editor>
</div>
</template>
<script>
import Toolbar from './Toolbar.vue'
import NotesList from './NotesList.vue'
import Editor from './Editor.vue'
import MessageList from './MessageList.vue'
export default {
components: {
Toolbar,
NotesList,
Editor,
MessageList
}
}
</script>
Main.js
import Vue from 'vue'
import store from './vuex/store'
import App from './components/App.vue'
new Vue({
store, // inject store to all children
el: 'body',
components: { App }
})
You could do this either by using v-if on each of the components, or by using dynamic components. In either case, your button should toggle a data value which would be used to control which component is displayed.