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
Related
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.
I have a Vuex store feeding many Vue components in a somewhat large web app. I would like to be able to watch Vuex states or getters for logging purposes. However, I want to be able to watch them 'globally', i.e. without relying on any particular Vue component. This rules out tricks like
//aComponent.vue
watch:{ '$store.state.data'(value, oldValue) { /*do something here*/ }}
and
//App.vue
created() {
this.$store.watch((state) => state.watchedState) => {/*do something here*/ })
}
Instead, I am looking for a way to watch my Vuex states or getters directly from the module where the store is defined, so that whenever a state changes, I can call a function passing it as arguments the old state and the new state, so as to write the change into a database (ideally the change itself would be detected automatically, as in Vue's watch(new,old) {...}.
I suppose I should use Vuex native method store.watch() for this purpose. But so far I have not be able to invoke it from the store module, as desired.
Any clue? Or did I miss something and what I am trying to do would be just as efficiently done with a different technique?
For watching mutations you have this options.
You can subscribe to a store and get notified by mutation after it happens.
store.subscribe( (mutation, state) => {
})
You can achieve this in a couple of ways:
use subscribe on the store you create by hand, most likely in main.js
create a plugin that gets appended to each instance of a store and again subscribe to it
just use the vuex official plugin for logging
For watching getters you probably need to monkey patch the getters property by hand.
Then again, if you want to watch what happens with vuex during development you can use vuejs tools
I have 3 Components in my 'Search' (parent) View; 'SearchForm', 'ResultList', 'DetailPage'. I switch from the SearchForm to the ResultList when I have received a response from the backend.
<keep-alive>
<component v-bind:is="currentComponent"></component>
</keep-alive>
When a response is recieved in my 'SearchForm' I save it to the searchBus;
searchBus.$emit('searchIssue', response.data);
Then, in my ResultList I want to retrieve it again and display the results;
mounted() {
searchBus.$on(['searchIssue'], (search) => {
this.table_items = search;
});
}
I display a loading animation (also a component) until the response is fully loaded and the ResultList is displayed.
Due to the Vue lifecycle everything is working when all components are displayed in one View, as they are already listening when the bus is updated.
Should I choose a different approach? E.g. using v-show or pass the response back to the Parent and inserting it again with a prop (Idk if it would work as not all components have the same props).
Is there a way to use the Bus anyway ? And how could it be solved making it one linear hierarchy and still hide the non-relevant components? (SearchForm -> ResultList -> DetailPage)
Should I choose a different approach?
I thing that is coming time for using Vuex
At the center of every Vuex application is the store. A "store" is
basically a container that holds your application state. There are two
things that make a Vuex store different from a plain global object:
Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state
changes.
You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations. This
ensures every state change leaves a track-able record, and enables
tooling that helps us better understand our applications.
I am trying to integrate Fine Uploader in my project which is built on Laravel & Vue. This project has a lot of legacy code that I have to support (such as old CSS classes, etc.) so I need to integrate Fine Uploader as a JS plugin, and can't use any existing 3rd party Vue Fine Uploader components that may be out there.
I've managed to get it to work for the most part. However, here is the challenge that I present to you. Below, you can see a screenshot of my code, in which I am instantiating the Fine Uploader instance inside my mounted hook.
As you can see I have highlighted the part of the code where I would emit an event when a new file is submitted for uploading. Here however, since I am inside the Fine Uploader instance, when I do this.$emit, it doesn't work (as it shouldn't).
I tried to circumvent this by using a global eventBus. This worked, but created issues when several files are dropped into the uploader at once. The event fires multiple times and often loses track of which event was fired by which instance, thus causing the 'thumbnails component' to perform duplicate actions.
I am convinced that I need to fire 'component-specific' events so that the thumbnail components that are generated and updated (onProgress and onComplete) only take their relevant actions once.
How can I fire component specific events from within another class instantiation?
Thank you.
Your function callbacks don't have their contexts bound, so this inside the callback does not refer to the Vue instance (which would result in $emit being undefined).
There are a few different solutions:
Use an arrow-function:
onSubmitted: (id, name) => {
// `this` is Vue instance
}
Bind the function context with Function#bind:
onSubmitted: function(id, name) {
// `this` is Vue instance
}.bind(this)
Use a cached reference to the Vue instance:
const vm = this;
const f = new qq.FineUploaderBasic({
// ...
onSubmitted: function(id, name) {
vm.$emit(...)
}
})
As the topic suggests, I have a particular item in my vuex store which I am bringing into my component in the computed properties section using mapState. This is the code for it:
computed: mapState({
orderTitle: state => state.order.bookTitle,
}),
When I inspect this in the Vuex section of Vue Dev Tools, I can see that it is accurately getting the data from the store.
Now the problem.
I have an input text field which I have put a v-model on, and associated it with a data property. What I want to do is pre-populate that text field with the text found in orderTitle which I am getting from my store.
I tried doing this by simply assigning the value in the computed property to the data property in the mounted hook. However, this didn't work.
When I tried to troubleshoot it by doing console.log(this.orderTitle) to see the value of the computed property in the mounted hook, it showed up as blank.
How come the value is properly appearing in the Vue Dev Tools (and even in the console when I do $vm0.orderTitle) but not in the mounted hook?
Any thoughts?
Thanks!
Sounds like a "this scope" problem.
Try with
computed: mapState({
orderTitle (state) {
return state.order.bookTitle
}
}),
I figured it out. Instead of performing the actions in the mounted hook, I did it in the updated hook, which fires much later in the Vue instance lifecycle (after the Virtual DOM is re-rendered & patched).