I want to import screens based on user id. I created a wrapper component to do this but It doesn't work for nested routes. In vue 2 I can use app instance in router to decide which screen renders but vue 3 I can't do this approach
<script>
//imports
export default {
setup() {
const decidedComponent = ref();
const { user } = useAuth();
const route = useRoute();
function decide() {
decidedComponent.value = markRaw(
defineAsyncComponent(() =>
user.id === 1
? import(`#/screens/1/${route.meta.name}/index.vue`)
: user.id === 2
? route.meta.name
: import(`#/screens/2/${route.meta.name}/index.vue`)
)
);
}
return {
decide,
decidedComponent,
};
},
beforeRouteEnter(to, from, next) {
// When first entering the route
next((vm) => vm.decide());
},
};
</script>
<template>
<component
v-if="decidedComponent"
:is="decidedComponent"
:key="`${decidedComponent.__file}`"
></component>
</template>
//router
{
path: "/customer/:customerId",
name: "customer",
component: DecideComponent,
meta: {
name: "MultiPages",
},
children: [
{
path: "details",
name: "customer.details",
component: DecideComponent,
meta: {
name: "CustomerDetails",
},
},
It doesn't work for parent route.
Related
I am using Vue3 option API and Pinia .
I want to call an action in Pinia option Api from component
component
import { mapActions } from "pinia";
import { useTableStore } from "../../../stores/table";
export default {
name: "LoggingForm",
data() {
return {
login: {
username: "",
password: "",
serverhost: "",
},
};
},
methods: {
submit(){
this.getData(this.login)
}
},
computed: {
...mapActions(useTableStore, ["getData"]),
},
};
and this is store/table.js
import { defineStore } from 'pinia'
import authService from "#/api/auth.js";
export const useTableStore = defineStore({
id: 'table',
state: () => ({
table: []
}),
getters: {
headers: (state) => state.table[0],
body: (state) => state.table.slice(1)
},
actions: {
async getData1(data) {
// do something
}
},
}
})
But I get this error
I can Use state and getters perfectly Just action don't work !
what's the problem ?
Here is what you need
https://pinia.vuejs.org/core-concepts/actions.html#without-setup
In short:
computed => mapGetters
methods => mapActions
You are using mapActions with computed so that will not work
i want to run a method when emitting how can i get it?
When handleShow(depth is clicked), I want to run collapsed in the medhod in the setup.
or
I want to trigger the function I will write in setup
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
methods: {
collapsed(dep) {
console.log(dep)
}
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
emit('clicked', depth)
}
return {
showDropdown,
handleShow,
}
},
};
</script>
emit should only be used if you want to get an event out of your component to its parent (for example, if your component is a custom button and you want its parent to specify what would happen when clicking on it). Otherwise, you can write the code you want inside of handleShow instead of calling emit. You can also change the function name to whatever you want, just make sure it's the same inside the setup method and in the #click.stop property.
In your case (since you just console.log the result):
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
console.log(depth)
// do whatever you want here
}
return {
showDropdown,
handleShow,
}
},
};
</script>
I am using Vue3 and have my Router setup for detail pages. Any title returns the same data and 404 is being ignored even after adding the regEx inside the routes.
Routes:
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import HomeView from "../views/HomeView.vue";
import ErrorView from "../views/ErrorView.vue";
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/about",
name: "about",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
},
{
path: "/article/:slug",
name: "article",
component: () =>
import(/* webpackChunkName: "article" */ "../views/ArticleView.vue"),
},
{
path: "/404",
name: "PageNotExist",
component: () => import("../views/ErrorView.vue"),
},
{
path: "/:catchAll(.*)", // Unrecognized path automatically matches 404
redirect: "/404",
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
Article:
<template>
<div>
<h1>{{ data.title }}</h1>
<h3>{{ data.textarea }}</h3>
</div>
</template>
<script lang="ts">
import { useSanityFetcher } from "vue-sanity";
import { defineComponent } from "vue";
export default defineComponent({
name: "ArticleView",
setup: () => {
const articleQuery = `*[_type == "article"][0] {
title,
textarea,
}`;
const options = {
listen: true,
clientOnly: true,
};
const { data } = useSanityFetcher<object>(articleQuery, options);
return { data };
},
});
</script>
I m using vis.js timeline and i want display date from firestore. It works when I type manually (look --> this.items), but does not work with firestore (look --> this.users).
I m using Vue framework.
<script>
export default {
data() {
return {
users: [],
items: [
{
id: '1',
content: 'London',
group: 'Mike',
start: '2021-12-20',
end: '2022-06-19',
},
],
}
},
async fetch() {
await this.loadPlaces()
},
methods: {
async loadPlaces() {
const querySnapshot = await getDocs(collection(db, 'places'))
querySnapshot.forEach((doc) => {
this.users.push({ id: doc.id, ...doc.data() })
})
this.$store.commit('places/setPlaces', this.users)
},
},
computed: {
places() {
return this.$store.state.places.places
},
},
mounted() {
let container = document.getElementById('visualization')
let options = {
moveable: true,
}
let timeline = new vis.Timeline(container)
timeline.setOptions(options)
timeline.setGroups(this.groups)
timeline.setItems(this.items)
},
}
</script>
I found a solution.
I just moved all code from mounted() to method loadPlaces (under this.$store.commit)
Save yourself trouble and use the vis datasets instead.
my pinia store in vue 3 looks like this.
import { defineStore } from 'pinia'
import { DataSet } from 'vis-data/esnext'
export const useVisData = defineStore('visData', {
state: () => ({
items: new DataSet([]),
groups: new DataSet([]),
selectedItems: [],
serializedGroupsAndItems: []
}),
actions: {
//Group actions
showAllGroups() {
this.groups.forEach(group => {
this.groups.updateOnly({ id: group.id, visible: true })
});
},
addGroup(group) {
this.groups.add(group)
},
hideGroup(group) {
this.groups.updateOnly({ id: group, visible: false })
},
//Item actions
addItem(item) {
this.items.add(item)
},
removeItem(item) {
this.items.remove(item)
},
setSelectedItems(items) {
this.selectedItems = items
},
//data add/remove
serializeData() {
this.serializedGroupsAndItems.push({
groups: JSON.stringify(this.groups.get()),
items: JSON.stringify(this.items.get())
})
},
loadSerializedData() {
this.clearGroupsAndItems()
this.serializedGroupsAndItems.forEach(data => {
this.addGroup(JSON.parse([data.groups]))
this.addItem(JSON.parse([data.items]))
})
},
//misc
clearGroupsAndItems() {
this.groups.clear()
this.items.clear()
}
},
getters: {
getHiddenGroups(state) {
return state.groups.get({
filter: (item) => {
return item.visible === false
}
})
}
}
})
Also remember to watch for changes in your options.
Might be better to wrap it in a vue component too. something like this.
this is what i did.
let timeline;
const visref = ref(null);
onMounted(async () => {
timeline = new Timeline(visref.value, props.items, props.groups, {...props.options, ...timelineOptions});
props.events.forEach(event => {
on(event, (properties) => {
// console.log(event, properties)
emits(`vis${event}`, properties);
});
});
})
<template>
<div ref="visref"></div>
</template>
then you can use it like so:
const timelineref = ref();
<Timeline
ref="timelineref"
:items="visStore.items"
:groups="visStore.groups"
:options="options"
/>
remember to expose the instance in your timeline component then you can call the functions using a ref like this.
timelineref.value.timeline.zoomOut(0.5)
I have some data in a firestore and want to display it in my vue app.
Firestore:
Test.vue
<template>
<p>{{ items }}</p>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: mapState(["items"]),
methods: {
getItems() {
this.$store.dispatch("bindItems");
},
},
mounted() {
this.getItems();
},
};
</script>
index.js
import { createStore } from "vuex";
import { firestoreAction } from "vuexfire";
import { vuexfireMutations } from "vuexfire";
import { db } from "./db";
const store = createStore({
state() {
return {
items: [],
};
},
actions: {
bindItems: firestoreAction(({ bindFirestoreRef }) => {
return bindFirestoreRef("items", db.collection("items"));
}),
},
mutations: {
...vuexfireMutations,
},
getters: {
items(state) {
return state.items;
},
},
});
store.subscribe((state) => console.log(state));
export default store;
To check my store, I added this line in index.js: store.subscribe((state) => console.log(state));. As it turns out, the data from firestore actually makes it to my store:
Why is it not rendered in the frontend? What do I have to change to make it appear?
Edit.
When I hardcode some data in my store and remove this.$store.dispatch("bisndItems"); from the monuted hook, the data gets rendered:
state() {
return {
items: {"name": "peter"},
};
},