hello good day i have a little question
If I want to access the validation function written in the setup from a method outside the setup, how can I do it with the onSubmit Function?
setup() {
const store = useStore();
const router = useRouter();
const loading = ref(false);
const validationSchema = Yup.object().shape({
email: Yup.string().trim().email().required().label("Email"),
password: Yup.string().trim().min(6).required().label("Parola"),
});
const { handleSubmit } = useForm({ validationSchema });
return {
loading,
validationSchema,
};
where i want to reach
methods: {
onSubmit() {
alert();
},
},
Related
I want to use useRoute inside my component which is called in onMounted hook.
Something like
import { checkUserAuth } from '#/common/CheckUserAuth'
onMounted(async () => {
await checkUserAuth()
})
And CheckUserAuth.ts is:
import { useRouter } from 'vue-router'
const router = useRouter() // here router is undefined
export const checkUserAuth = async () => {
const userStore = useUserStore()
const userApi = new UserApi()
const token = localStorage.getItem(TOKEN_NAME)
const router = useRouter() // and here too router is undefined
if (!token) {
await router.push({ name: LOGIN_PAGE_ROUTE })
return
}
const userData = await userApi.fetchMasterInfo()
userStore.setUser(userData)
await router.push({ name: DASHBOARD_ROUTE })
}
I don't understand why the router is indefined everywhere and is it possible to solve this without passing the router as an argument? (i want to make the checkUserAuth function fully encapsulated)
i know i can fix it like
const router = useRouter()
onMounted(async () => {
await checkUserAuth(router)
})
export const checkUserAuth = async (router: Router) => {
await router.push({ name: DASHBOARD_ROUTE })
}
But it's not good solution
The API of useRouter must be called in setup, as mentioned in the official document. You can see this point in https://router.vuejs.org/zh/api/#userouter(zh document mentioned it).
Maybe you can write code like this:
import { useRouter } from 'vue-router'
export const useCheckUserAuth = () => {
const userStore = useUserStore()
const router = useRouter()
returnv aysnc function checkUserAuth() {
const userApi = new UserApi()
const token = localStorage.getItem(TOKEN_NAME)
if (!token) {
await router.push({ name: LOGIN_PAGE_ROUTE })
return
}
const userData = await userApi.fetchMasterInfo()
userStore.setUser(userData)
await router.push({ name: DASHBOARD_ROUTE })
}
}
And call it in setup:
const checkUserAuth = useCheckUserAuth()
onMounted(() => {
checkUserAuth()
})
hope it can help you.
Composables are supposed to be used directly in setup, unless their implementation allows for other usage, this needs to be determined for each case.
Since checkUserAuth uses composables, this makes it a composable either, in case it needs to be used in mounted hook, it needs to return a function that allows this:
const useUserAuth = () => {
const router = useRouter()
const userStore = useUserStore()
const userApi = new UserApi()
return {
async check() {...}
}
}
Alternatively, checkUserAuth shouldn't use composables. useUserStore doesn't have restrictions that are inherent to composable, and useRouter can be replaced with an import of router instance.
Im devoloping a Vue Frontend and my problem is the flow between Vuex and vue component.
Vuex component
const state = () => ({
User: {
Firstname: '',
Lastname: '',
MainAccountBalance: '',
SubAccount: []
}
})
const getters = {
getUserData(state) {
console.log("3 Dashboard: getter")
return state.User;
}
};
const actions = {
async fetchUserProfile({commit}, payload) {
await instance.post(UserAccounts, {
token: payload.token
})
.then(response => {
console.log("1 Dashboard: fetchUserProfile");
commit('saveAccounts', response.data);
return JSON.stringify(response.data);
})
}
};
const mutations = {
saveAccounts(state, data) {
const newModel = {
Firstname: data.Firstname,
Lastname: data.Fastname,
MainAccountBalance: data.MainAccountBalance,
SubAccount: data.SubBankAccounts
}
console.log("2 Dashboard: Mutations")
state.User = newModel;
}
};
fetchUserProfile is getting called from Vue component and gets commited to saveAccounts where it will set data for state variables. All of this works fine, and in correct order. The problem starts with when i want to get the data from the State using getters.
Vue component
computed: {
...mapGetters("auth", {
getUserData: 'getAuthData'
}),
},
methods: {
...mapActions("dashboard", {
userProfileaction: "fetchUserProfile"
}),
getUserToken() {
this.access_token = localStorage.getItem("access_token")
return this.access_token;
},
async saveUserData() {
var userToken = this.getUserToken();
await this.fetchUserProfile({token: userToken})
this.Firstname = this.getUserData.Firstname;
this.Lastname = this.getUserData.Lastname;
console.log("Last Show accounts: "+ this.getUserData.User.Firstname)
}
},
mounted() {
this.saveUserData()
console.log("test")
}
How would i use getters correct so it doesent execute before the variables are set on Vuex? Is there an better alternative way?
I have the following problem while trying to unit test my Vue application.
Even spying and mocking $router.push, I still can't make it to be called while inside unit testing:
This is my unit testing (Home.spec.js)
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueRouter);
describe('Home.vue', () => {
let actions;
let getters;
let store;
let router;
beforeEach(() => {
actions = {
[FETCH_USER_REPOSITORIES]: jest.fn()
};
getters = {
getTopThreeRepositories: jest.fn(repositoryMock.getRepositories)
};
store = new Vuex.Store({ getters, actions });
router = new VueRouter();
});
it('should redirect when 404 status code received', async () => {
jest.spyOn(store, 'dispatch').mockRejectedValue({ statusCode: 404 });
jest.spyOn(router, 'push').mockResolvedValue({});
const wrapper = await shallowMount(Home, {
store,
localVue,
router
});
expect(router.push).toHaveBeenCalledWith('/not-found');
});
});
Now, this is my Home.vue:
import { mapGetters } from 'vuex';
import { FETCH_USER_REPOSITORIES } from "../store/actions";
import RepositoryList from "#/components/RepositoryList";
import Card from "#/components/Card";
export default {
name: 'view-home',
components: {
Card,
RepositoryList
},
async beforeMount() {
try {
await this.$store.dispatch(FETCH_USER_REPOSITORIES, 'some-repo');
} catch(err) {
console.log(this.$router);
await this.$router.push('/not-found');
}
},
computed: {
...mapGetters(["getTopThreeRepositories"])
}
}
The console log shows the $router correctly, with the spy.
If I force the calling inside the unit testing, it works, but the expects always fails giving me back that $router.push hasn't been called.
Can anyone help me, please?
Thanks!
You should specify $store and $route as mocks in your mounting options, as shown below. Also there's no need to await shallowMount because shallowMount does not return a Promise, so the await would just return immediately.
describe('Home.vue', () => {
it('should redirect when 404 status code received', () => {
const $store = {
dispatch: jest.fn()
}
const $router = {
push: jest.fn()
}
const wrapper = shallowMount(Home, {
localVue,
mocks: {
$store,
$router,
}
});
expect($router.push).toHaveBeenCalledWith('/not-found');
})
})
I need to get remote data to be displayed in every pages.
This call is perfomed in store/index.js:
export const state = () => ({
contact: {
hello: "World"
}
});
export const actions = {
async nuxtServerInit({ commit, state }) {
const { contactData } = await this.$axios.get("/contact");
commit("SET_CONTACT", contactData);
}
};
export const mutations = {
SET_CONTACT(state, contactData) {
state.contact = contactData;
}
};
Problem is that the value of contact turns to undefined in the store, whereas expected content is retrieved through Axios (the retrieved content is displayed in the SSR console...)
What am I missing here?
export const actions = {
async nuxtServerInit({ commit, state }, {app} ) {
const { contactData } = await app.$axios.get("/contact");
commit("SET_CONTACT", contactData);
}
};
I am trying to pre-fetch some data and update Vuex before client-side kicks in.
store/index.js
export const state = () => ({});
export const getters = {};
export const actions = {
async nuxtServerInit ({ dispatch }) {
await dispatch('nasa/getImages');
}
};
store/moduleName.js
import fetch from 'node-fetch';
export const state = () => ({
images: []
});
export const mutations = {
storeImages(state, data) {
state.images = [];
state.images.push(...data);
console.log(state.images[0]); <- this logs in the terminal
}
}
export const actions = {
getImages(store) {
return fetch('api/url').then(response => {
response.json().then(function(data) {
store.commit('storeImages', data.collection.items.slice(0, 24));
});
});
}
}
My mutation gets triggered by nuxtServerInit and I am getting the first element logged in the terminal on page load. My store in the client-side however, is empty.
What am I missing?
With help from a friend we have managed to fix this issue by removing node-fetch and adding axios to Vuex instead.
The only change made was in store/moduleName.js which now looks like:
import Axios from 'axios'
export const state = () => ({
images: []
});
export const mutations = {
storeImages(state, data) {
state.images.push(...data);
}
}
export const actions = {
async getImages(store) {
let res = await Axios.get('api/url');
store.commit('storeImages', res.data.collection.items.slice(0, 24));
}
}