Context
i have a User object which is the data model for a vue.js UserComponent. When the component is mounted the user has undefined fields. Then inside the mounted() method the user is fetched from the server and all its fileds are setted.
Problem
So i found that vue-test-utils doesn't redraw component when user's fields changed.
Note
On the other hand the same test works good if i change object prop to scalar.
I tried to reset user prop by wrapper.setProp({user: user}) after its fields was fetchad. Unfortunatelly it is impossible as vue-test-utils preventing to set the same object to prop.
Demo repo (cloned from official vue-test-utils-getting-started)
https://github.com/alexey2baranov/vue-test-utils-getting-started
When your component have async methods, like fetch user fields on mounted, you have two options when testing:
Option 1: Test with an async function and await for the nextTick
Option 2: Use the package flush-promises
Both options are detailed in the vuejs test utils documentation with examples.
Also, you can mock axios response with some data for populate your user fields without a real fetch to your backend.
Related
In options api,its obvious where we write code for fetching the data from server in mounted method.
With composition api,i am confused as the setup method is the one that loads first before the onMounted hook.
Check their docs: https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram
If you are doing DOM related actions, you would want to do it in onMounted() hooks, because setup() doesn't have access to DOM yet.
So I would probably do it in onMounted() methods since I would probably store result from API to component data or may update DOM as a side-effect.
I have a VueJS component that I'd like to debug. I need to check the behaviour of a getter in the browser. Is it possible to call it manually from the browser console?
Edit: This link contains some info on how to trigger a state change manually: https://forum.vuejs.org/t/forcing-a-refresh-to-a-getter/32922
Especially:
a mutation update to a state collection such as:
state.items = {}
in mutations:
state.items[item.key] = item // does not trip off detection
instead use this
Vue.set(state.items, item.key, item) // this does trip detection.
There's a few ways of doing this:
Use vue-devtools. You can see Vuex store there in the Vuex tab, so you can do some debugging visually.
Or make Vue available globally window.App = new Vue(....)). You will be able to get Vue instance as window.App
Or, as it was suggested in the comments, you could run console.log(this.$state.getters) somewhere in the app, then in the console right click on that output and click "Store as global variable" which will make it available as temp1. Then you can access it as temp1.someGetterName
In my vue cli project I have a route Settings with 3 child components SettingsA, SettingsB and SettingsC. Each child component has ca. 15 input fields, so it would be too many input fields for one single component.
The goal is to get data from a REST backend with an an axios call when the Route Settings is loaded, and populate some of the input fields with the data;
the user can then navigate between the child components and fill/change the input fields, without triggering the axios call which would reload and overwrite the users input field changes.
Since there are 3 child components I use vuex as store. That way the users inputs should not change when he navigates between the child components.
My question is: Where and with what hook should I make the axios call? With beforeMounted on the Settings Component?
Maybe there is also a better, already tried design than mine?
Thanks for your help!
Solution using custom events
You actually not necessarily need vuex. Basic idea is to have parent component Settings, which includes SettingsA, SettingsB and SettingsC, which are displayed conditionally using v-if. The Settings component is holding your state. Changes in the child components form fields trigger events with this.$emit(). The parent component listens to the events and updates its state. The state of the form is passed down via props.
Solution using Vuex actions
If you go the Vuex route, you will trigger actions instead of using this.$emit() and update the global store. You should import the actions using mapActions. In your components you then have access to the global store using this.$store.
I am using Inertiajs
with Laravel and also trying to use Element UI components but as i use Menu component i am having following error in console, I just used example as given in Element Ui Components as i was testing.
I see 2 different errors in there, both of them are with props.
I assume your component is taking the route as a prop, and you are also using the route as a method, which you might have put inside methods: {} which is not allowed. Make sure you rename your method route to something else.
Note: As a matter of fact you can't have any data coinciding with each other. your props, data, computed props and methods all should have unique names.
You are trying to use v-model on the props directly which won't work in Vue. if the prop is a primitive (Number, String, Boolean etc). but you can pass Object or an Array which can hold a reference to the data. This is because reactivity in Vue can't keep track of props when passed as primitives.
More on prop mutations here: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
I have webpack setup to bundle all of the source. I have a Vue object that is the page and multiple Vue components of my own creation. This works great!
I am now getting reference data from the database to fill in certain default options for some of these components. In my pages Mounted or Created events (there is no difference for my question) I am calling a method that will check to see if the data exists in localStorage and if not, it will extract the data from the database.
Once Extracted, I have it in localStorage so it is not an issue. However, the first time I need to gather the data (or when I need to refresh it because I have another trigger that lets me know when it has changed) the page and components have rendered (with errors because of lack of data) before the data comes back. The fetch method is in a promise, but mounted events don't seem to care if a promise exists within in before it continues to the next component.
So what is the best practice for loading/refreshing reference data in Vue? I am currently not using VueX because this is not a SPA. Sure, it is a single page that is doing things (there are many single pages that do their own thing in this site) but I have no need to make it a full SPA here. But If VueX and its store will give me some sort of guarantee that it will occur first or page/components will run AFTER VueX things, I will learn it.
Have you tried doing so:
<component v-if="page.isDataLoaded">...</component>
in your Vue-component:
data() {
return {
page: {
isDataLoaded: false,
}
}
},
mounted() {
this.fetchPageData().then(() => this.page.isDataLoaded = true);
}
You can use v-if and v-else to show, for example page loader element like so:
<PageLoader v-if="!page.isDataLoaded"></PageLoader>
<component v-else>...</component>