Global EventBus to pass data between components does not work - vue.js

I am trying to use a global eventbus in VueJs but have been unsuccessful so far.
I have the following code. When I navigate from ResetPassword to Login screen, I should see the successMessage with a Your password has been changed successfully. Please login to continue but it always shows a blank.
What could I be doing wrong?
plugins.js:
Vue.prototype.$eventHub = new Vue();
ChangePassword.vue:
methods:
{
ChangePassword()
{
this.$eventHub.$emit('navigation-message', 'Your password has been changed successfully. Please login to continue.');
this.$router.push({ name: 'login'});
},
},
Login.vue:
data() {
return {
successMessage:'',
};
},
created ()
{
this.$eventHub.$once('navigation-message', this.successMessage);
},
beforeDestroy()
{
this.$eventHub.$off('navigation-message');
},
Update: 12/8/2019: I changed the login.vue as per comment by #tony19 but the issue still exists.
Login.vue:
created ()
{
this.$eventHub.$once('navigation-message', (payload)=>
{
updateSuccessMessage(payload);
});
},
methods:
{
updateSuccessMessage(payload)
{
this.successMessage=payload;
},

You need to add this.
created () {
this.$eventHub.$on('navigation-message', payload => {
this.updateSuccessMessage(payload)
})
},
methods: {
updateSuccessMessage(payload) {
this.successMessage = payload
}
}
Also make sure you're actually importing plugin.js globally (e.g. inside your main file where you import Vue) and make sure your components have access to it.
Try this:
created() {
console.log(this.$eventHub)
}

Related

Nuxtjs auto log out user inactive

I'm using Nuxtjs for my project. I need to logout the user if there is not active after a given time frame. I'm creating a new component name autologout.vue and add this code to it
autologout.vue
<template>
<div>
hello
<div v-if="warningZone">warning</div>
</div>
</template>
<script>
export default {
data() {
return {
events: ['click', 'mousemove', 'mousedown', 'scroll', 'keypress', 'load'],
warningTimer: null,
logoutTimer: null,
warningZone: false,
}
},
mounted() {
this.events.forEach(function (event) {
window.addEventListener(event, this.resetTimer())
}, this)
this.setTimers()
},
destroyed() {
this.events.forEach(function (event) {
window.removeEventListener(event, this.resetTimer())
}, this)
this.resetTimer()
},
methods: {
setTimers() {
this.warningTimer = setTimeout(this.warningMessage(), 4 * 1000)
this.logoutTimer = setTimeout(this.logoutuser(), 10 * 1000)
this.warningZone = false
},
warningMessage() {
this.warningZone = true
},
logoutuser() {
this.$auth.logout('local').then((data) => {
console.log(data)
})
},
resetTimer() {
clearTimeout(this.warningTimer)
clearTimeout(this.logoutTimer)
this.setTimers()
},
},
}
</script>
<style></style>
add import this component to layout->default.vue. I'm not using default.vue layout to my login page. after I'm login and redirect to the home page it always logout me. What is wrong?
I'm using this tutorial to implement this
Tutorial link
Although it is not a perfect way to handle the problem, but if you remove the parentheses present inside the addEventListener function, it will start working.
Change
window.addEventListener(event, this.resetTimer())
To
window.addEventListener(event, this.resetTimer)
And if you remove the paratheses from removeEventListener, it will again stop working. Don't know why.

Action is not defined as a method in the component vue.js

I'm trying to access an action as a method in component, But got error of
this.delete_notifaction is not a function
notifaction.js
export const actions = {
add_notifaction({ commit }, notifaction) {
commit("ADD_NOTIFACTION", notifaction);
},
delete_notifaction({ commit }, notificationToRemove) {
commit('DELETE_NOTIFACTION', notificationToRemove)
}
};
store/index.js
modules : {
notifaction
},
Component.vue
methods: mapActions('notifaction',["delete_notifaction"]),
mounted() {
this.delete_notifaction(this.notification);
}
Any Help?
Try this
methods: {
...mapActions(['delete_notifaction']),
}
See here for spread syntax
https://stackoverflow.com/a/48137766/10118668

How to track changes to the injected root instance property

I have a property injected like so:
Vue.prototype.$authentication = {
authenticated: false,
user: ""
};
and its working fine.
then in another component I want to track/watch the property changes. How do I do it ?
EDIT
I want to be able to do it like this:
<script>
export default {
name: "Login",
data: function(){
return {
isLoggedIn: this.$authentication.authenticated
}
},
watch: {
isLoggedIn(){
console.log('its working');
}
},
}
</script>
but the thing is, the code wouldn't work.
Have it solved by looking at the api doc. So in my component file, I simply do it like so:
<script>
export default {
name: "Login",
data: function(){
return {
isLoggedIn: this.$authentication // remove the attribute
}
},
watch: {
'isLoggedIn.authenticated': function (){ // now access the attribute
console.log('its working');
}
},
}
</script>
now it is all good.

Async changes to properties

New to vuejs.
I have a vue with the following script (code shortened):
export default {
mixins: [asyncStatuses],
props: {
value: { type: Object }
},
data() {
return {
statuses: []
};
},
computed: {
hasStatuses() {
return this.statuses && this.statuses.length > 0;
}
},
beforeMount() {
// This is an async call
this.getStatuses().then((response) => {
this.statuses = response.data.statuses;
});
}
};
In my .vue file, I do something like this:
<div v-if="hasStatuses">
<div>Show a list of statuses</div>
</div>
The problem is the <div> never shows up. The statuses are loading correctly. I put a debugger in the computed.hasStatuses but it never runs?
Can anyone explain to me how and why this is happening and how to fix it?
Thanks again!!
The code is setting self.statuses, but self is not defined.
self.statuses = response.data.statuses
Just use this.
this.statuses = response.data.statuses

Update VueJs component on route change

Is there a way to re-render a component on route change? I'm using Vue Router 2.3.0, and I'm using the same component in multiple routes. It works fine the first time or if I navigate to a route that doesn't use the component and then go to one that does. I'm passing what's different in props like so
{
name: 'MainMap',
path: '/',
props: {
dataFile: 'all_resv.csv',
mapFile: 'contig_us.geo.json',
mapType: 'us'
},
folder: true,
component: Map
},
{
name: 'Arizona',
path: '/arizona',
props: {
dataFile: 'az.csv',
mapFile: 'az.counties.json',
mapType: 'state'
},
folder: true,
component: Map
}
Then I'm using the props to load a new map and new data, but the map stays the same as when it first loaded. I'm not sure what's going on.
The component looks like this:
data() {
return {
loading: true,
load: ''
}
},
props: ['dataFile', 'mapFile', 'mapType'],
watch: {
load: function() {
this.mounted();
}
},
mounted() {
let _this = this;
let svg = d3.select(this.$el);
d3.queue()
.defer(d3.json, `static/data/maps/${this.mapFile}`)
.defer(d3.csv, `static/data/stations/${this.dataFile}`)
.await(function(error, map, stations) {
// Build Map here
});
}
You may want to add a :key attribute to <router-view> like so:
<router-view :key="$route.fullPath"></router-view>
This way, Vue Router will reload the component once the path changes. Without the key, it won’t even notice that something has changed because the same component is being used (in your case, the Map component).
UPDATE --- 3 July, 2019
I found this thing on vue-router documentation, it's called In Component Guards. By the description of it, it really suits your needs (and mine actually). So the codes should be something like this.
export default () {
beforeRouteUpdate (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params `/foo/:id`, when we
// navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
// will be reused, and this hook will be called when that happens.
// has access to `this` component instance.
const id = to.params.id
this.AJAXRequest(id)
next()
},
}
As you can see, I just add a next() function. Hope this helps you! Good luck!
Below is my older answer.
Only saved for the purpose of "progress"
My solution to this problem was to watch the $route property.
Which will ended up you getting two values, that is to and from.
watch: {
'$route'(to, from) {
const id = to.params.id
this.AJAXRequest(id)
}
},
The alternate solution to this question handles this situation in more cases.
First, you shouldn't really call mounted() yourself. Abstract the things you are doing in mounted into a method that you can call from mounted. Second, Vue will try to re-use components when it can, so your main issue is likely that mounted is only ever fired once. Instead, you might try using the updated or beforeUpdate lifecycle event.
const Map = {
data() {
return {
loading: true,
load: ''
}
},
props: ['dataFile', 'mapFile', 'mapType'],
methods:{
drawMap(){
console.log("do a bunch a d3 stuff")
}
},
updated(){
console.log('updated')
this.drawMap()
},
mounted() {
console.log('mounted')
this.drawMap()
}
}
Here's a little example, not drawing the d3 stuff, but showing how mounted and updated are fired when you swap routes. Pop open the console, and you will see mounted is only ever fired once.
you can use just this code:
watch: {
$route(to, from) {
// react to route changes...
}
}
Yes, I had the same problem and solved by following way;
ProductDetails.vue
data() {
return {
...
productId: this.$route.params.productId,
...
};
},
methods: {
...mapActions("products", ["fetchProduct"]),
...
},
created() {
this.fetchProduct(this.productId);
...
}
The fetchProduct function comes from Vuex store. When an another product is clicked, the route param is changed by productId but component is not re-rendered because created life cycle hook executes at initialization stage.
When I added just key on router-view on parent component app.vue file
app.vue
<router-view :key="this.$route.path"></router-view>
Now it works well for me. Hopefully this will help Vue developers!
I was having the same issue, but slightly different. I just added a watch on the prop and then re-initiated the fetch method on the prop change.
import { ref, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import Page from './content/Page.vue';
import Post from './content/Post.vue';
const props = defineProps({ pageSlug: String });
const pageData = ref(false);
const pageBodyClass = ref('');
function getPostContent() {
let postRestEndPoint = '/wp-json/vuepress/v1/post/' + props.pageSlug;
fetch(postRestEndPoint, { method: 'GET', credentials: 'same-origin' })
.then(res => res.json())
.then(res => {
pageData.value = res;
})
.catch(err => console.log(err));
}
getPostContent();
watch(props, (curVal, oldVal) => {
getPostContent();
});
watch(pageData, (newVal, oldVal) => {
if (newVal.hasOwnProperty('data') === true && newVal.data.status === 404) {
pageData.value = false;
window.location.href = "/404";
}
});
router - index.js
{
path: "/:pageSlug",
name: "Page",
component: Page,
props: true,
},
{
path: "/product/:productSlug",
name: "Product",
component: Product,
},
{
path: "/404",
name: "404",
component: Error404,
}