Component to emit event on mapGetters - vue.js

So I load my component, I then call the do something like the following:
created() {
this.$store.dispatch('messages/connect');
this.$store.dispatch('messages/fetchAllMessages');
// this.$emit('set-recipient', this.chats[0]);
},
computed: mapGetters('messages', {
chats: 'getMessages'
}),
The commented section within created is the snippet that I would like to run but only on the creation of this.chats and not on any update there after.
If I try to emit the event where it currently is I get an error: Cannot read property '0' of null.
Hopefully you understand what I mean.
Any ideas?

fetchallMessages calls your server to get the messages, right? that asynchonous process won'T be finshed when the meit is run like that.
If you make sure to return a Promise from that action which resolves after you have added chats, you can do this:
this.$store.dispatch('messages/fetchAllMessages')
.then(() => {
this.$emit('set-recipient', this.chats[0]);
})
If you have trouble returning a Promise from that action, share its implementation and we'll fix it.

If i understand correctly, you want to execute this.$emit('set-recipient', this.chats[0]); only after chats was initialized.
You have 2 options:
don't use mapGetters for the chats getter, just define the computed yourself:
computed: {
...mapGetters('messages')
chats(){
const messages = this.$store.getters.getMessages;
if (messages.length){
this.$emit('set-recipient', this.chats[0]);
}
return messages;
}
}
Instead of doing it in the component, you can move the logic to the store and emit the event from there when you modify chats

Related

How to call a method after Vuex data is available?

I would like to call a method once, as soon as possible after its component loads, but it needs to be after a computed property that gets data from Vuex is defined.
For example:
computed: {
my_data: function() {
return this.$store.state.my_data;
}
},
methods: {
useData: function(){
axios.post('api/fetch', {'data': this.my_data});
}
},
mounted() {
this.useData(); //error: this.my_data is undefined;
},
watch: {
my_data: function(){
this.useData(); //never triggers
}
}
If I call this.useData() from mounted, my_data is still undefined. I tried setting a watcher on my_data, but it never triggers. I feel like I'm missing something obvious here.
Make sure the data in my_data is updating correctly in store. If still have issue, then use deep to watch my_data
watch:{
my_data:{
handler:function(){
this.userData();
},
deep:true
}
}
If you're using watch to trigger method, don't need to use to call it from the mounted.
It turns out the "undefined" error was caused by another object that shared a key name with my stored object. Unfortunately, the nebulous error message sent me on a wild goose chase after I assumed the stored object was the issue based on my inexperience with Vuex.

access methods from the vue current component

Can any one guide or suggest how to resolve this below issue.
Use Case: Trying to implement notification component
Scenario: I am trying to call a method or change the state of the data on triggering of event in Vue.
I have defined the event listener on mounted function and trying to access one of the method.
Basically, the alert within event function is getting triggered, where as alert inside method is not getting triggered, and even any data manipulation is not executing even with in event function.
Where am i missing? is it incorrect to alter state within Event listener?
Basically i am trying to implement notification feature which automatically disappear after few seconds
Any help is appreciated.
Thanks,
Girish
There is another reason,this inside callback function is not Vue component. You can assign var self = this and use inside the callback, or use arrow function.
mounted: function () {
var self = this
EventBus.$on('show', function () {
self.test()
self.show = true
})
},
methods: {
test () {
console.log('Inside methods')
}
}
I believe your problem is the spelling error instead of
method: {}
, use methods: {}
Example:
Error.
method: {
test: function () {
alert('Inside Method');
}
correct.
methods: {
test: function () {
alert('inside method);
}
}
I know it does not have much to do with the question, but be careful when using the event bus, it would be as if you had a speaker, and shouted in the middle of a crowd the name of a person.
Example:
eventbus says Hamilton in the midst of a crowd of 10,000 people.
How many Hamiltons can you have in the middle of this crowd? Use something more specific, such as parent-child communication, avoid using the event bus.

vue2: can not find a proper way to initialize component data by ajax

I have a component whose data is initialized by ajax. I know vue.js has provide several lifecycle hooks: Lifecycle-Diagram. But for ajax to initialize the data, which hook(beforeCreate, create, mounted, etc) is the best place to do it:
hook_name: function() {
ajaxCall(function(data) {
me.data = data;
});
}
Currently, i do it in mounted, making it to re-render the component. But i think we should get the data before the first render. Can someone figure out the best way to do it?
If you want to initialize your component with data you receive from a request, created() would be the most appropriate hook to use but it is a request, it might not resolve by the end of created or even mounted() (when even your DOM is ready to show content!).
So do have your component initialized with empty data like:
data () {
return {
listOfItems: [],
someKindOfConfig: {},
orSomeSpecialValue: null
}
}
and assign the actual values when you receive them in your created hook as these empty data properties would be available at that point of time, like:
created () {
someAPICall()
.then(data => {
this.listOfItems = data.listOfItems
})
/**
* Notice the use of arrow functions, without those [this] would
* not have the context of the component.
*/
}
It seems like you aren't using (or aren't planning to use) vuex but I'd highly recommend you to use it for for managing your data in stores. If you use vuex you can have actions which can make these api calls and by using simple getters in your component you would have access to the values returned by the request.

Best practice to change the route (VueRouter) after a mutation (Vuex)

I've searched a lot, but there is no clear answer to that. Basically, what should be the best practice to automatically change a route after a mutation?
Ex: I click a button to login() -> action login that makes an http call -> mutation LOGIN_SUCCESSFUL -> I want to redirect the user to the main page $router.go()
Should I wrap the action in a Promise, and then listen to the result to call the route change from the component?
Should I do it directly from the $store?
Does vuex-router-sync helps in any way?
Thanks a lot!
The answer to this questions seems to be somewhat unclear in the Vue community.
Most people (including me) would say that the store mutation should not have any effects besides actually mutating the store. Hence, doing the route change directly in the $store should be avoided.
I have very much enjoyed going with your first suggestion: Wrapping the action in a promise, and changing the route from withing your component as soon as the promise resolves.
A third solution is to use watch in your component, in order to change the route as soon as your LOGGED_IN_USER state (or whatever you call it) has changed. While this approach allows you to keep your actions and mutations 100% clean, I found it to become messy very, very quickly.
As a result, I would suggest going the promise route.
Put an event listener on your app.vue file then emit en event by your mutation function. But I suggest you wrapping the action in a promise is good way
App.vue:
import EventBus from './eventBus';
methods: {
redirectURL(path) {
this.$router.go(path)}
},
created() {
EventBus.$on('redirect', this.redirectURL)
}
mutation:
import EventBus from './eventBus';
LOGIN_SUCCESSFUL() {
state.blabla = "blabla";
EventBus.$emit('redirect', '/dashboard')
}
As of now (mid 2018) API of Vuex supports subscriptions. Using them it is possible to be notified when a mutation is changing your store and to adjust the router on demand.
The following example is an excerpt placed in created() life-cycle hook of a Vue component. It is subscribing to mutations of store waiting for the first match of desired criteria to cancel subscriptions and adjust route.
{
...
created: function() {
const unsubscribe = this.$store.subscribe( ( mutation, state ) => {
if ( mutation.type === "name-of-your-mutation" && state.yourInfo === desiredValue ) {
unsubscribe();
this.$router.push( { name: "name-of-your-new-route" } );
}
} );
},
...
}

Emit an event when a specific piece of state changes in vuex store

I have a Vuex store with the following state:
state: {
authed: false,
id: false
}
Inside a component I want to watch for changes to the authed state and send an AJAX call to the server. It needs to be done in various components.
I tried using store.watch(), but that fires when either id or authed changes. I also noticed, it's different from vm.$watch in that you can't specify a property. When i tried to do this:
store.watch('authed', function(newValue, oldValue){
//some code
});
I got this error:
[vuex] store.watch only accepts a function.
Any help is appreciated!
Just set a getter for the authed state in your component and watch that local getter:
watch: {
'authed': function () {
...
}
}
Or you can use ...
let suscribe = store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
// call suscribe() for unsuscribe
https://vuex.vuejs.org/api/#subscribe