I have a VueJS component where I listen for pushMessageEvent :
<template>
<div>
<VueBotUI
:options="options"
:is-open="isOpen"
:bot-typing="botTyping"
:input-disable="inputDisable"
:messages="messages"
#msg-send="onSend"
></VueBotUI>
</div>
</template>
<script>
export default {
components: {
VueBotUI
},
data: function () {
return {
options: {botTitle: 'test',},
user: {msg: null,},
msgRegex: /^[a-zA-Z ]+$/,
messages: []
}
},
mounted() {
document.addEventListener('pushMsgEvent', this.printPush);
},
beforeDestroy () {
document.removeEventListener('pushMsgEvent', this.printPush);
},
methods: {
printPush (e) {
console.log(e)
console.log("------------------")
console.log(e.detail)
},
}
}
</script>
And I want to fire this pushMessageEvent when I get a Push event in my service-worker:
/* eslint-disable */
importScripts(
"https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"
);
// Load all ENVERYWHERE enviroment variables
importScripts('./env-vars.js')
const PushMsgEvent = new CustomEvent('pushMsgEvent', { detail: null });
workbox.core.skipWaiting();
workbox.core.clientsClaim();
self.__WB_MANIFEST;
// Listen to push event
self.addEventListener("push", (event) => {
if (event.data) {
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
PushMsgEvent.detail = event.data.text();
//document.dispatchEvent(PushMsgEvent);
}
});
workbox.precaching.precacheAndRoute([]);
but I can't use document.dispatchEvent since I get document is not defined, is it a workaround to fire this event and catch it in my component ?
I have read about workbox-window but I can't figure out how to fire my event from the service-worker in order to catch it in the component
My solution:
service-worker.js:
// Listen to push event
self.addEventListener("push", (event) => {
if (event.data) {
self.clients.matchAll().then(clients => {
clients.forEach(client => {
client.postMessage(JSON.stringify(event.data.text()));
});
});
}
});
my component.vue :
mounted() {
navigator.serviceWorker.addEventListener('message', event => {
let msg = event.data;
this.printPush(msg);
});
},
beforeDestroy () {
navigator.serviceWorker.removeEventListener('message', event => {
this.printPush(event);
});
},
methods: {
printPush (e) {
console.log(e)
}
}
Related
I want to add window.addEventListener in vue js file.
window.addEventListener('message', (event) => {
console.log(event, ' i am here');
});
I have added this in mounted() function.
Now, I need to remove this in destroyed method but somehow I am not able to do it.
window.removeEventListener('message', (event) => {
console.log(event, ' i am here');
});
Ok So I have created a fiddle that will show you how to remove and add the message handler and how to post message it's here:
new Vue({
el: "#app",
methods: {
addHandler: function() {
window.addEventListener('message', this.eventListenerExample);
},
removeHandler: function(){
window.removeEventListener('message', this.eventListenerExample);
},
postMessage: function() {
window.postMessage("This is a message ");
},
eventListenerExample: function(event){
console.log(event, ' i am here');
}
},
mounted: function () {
this.addHandler();
},
destroyed: function() {
this.remveHanlder();
}
})
https://jsfiddle.net/ob1pLd7z/8/
Note here that the function is part of this vue instance and the function itself is added and removed rather than using an inline function like you originally showed.
I am happy to read that you want to clear/remove listener after component destroy
mounted() {
const listener = () => {}
const event = 'message'
window.addEventListener(event, listener)
this.$once('hook:destroyed', () => {
window.removeEventListener(event, listener)
})
}
You can use destroyed() or beforeDestroy() to remove the event listener.
To add event use mounted() like this,
mounted() {
window.addEventListener('event', listener);
}
ex:
mounted() {
window.addEventListener('keyup', this.navigateMovements);
}
and in templates main div,
<div #event='listener($event)'>
......
......
......
</div>
ex:
<div #keyup='navigateMovements($event)'>
......
......
......
</div>
To destroy the event
beforeDestroy() {
window.removeEventListener('event', listener);
}
ex:
beforeDestroy() {
window.removeEventListener('keyup', this.navigateMovements);
}
or use destroyed()
destroyed() {
window.removeEventListener('event', listener);
}
I'm studying javascript and mithril.js 1.1.6. I'm writing down a simple web app in which users land on a page where he can login. Users who already did login land on a different page. I'm trying this using conditional routing, here is the main component:
const m = require("mithril");
...
import Eventbus from './whafodi/eventbus.js';
import WelcomePage from './ui/welcome.js';
import User from './model/user.js';
var eventbus = new Eventbus();
function MyApp() {
return {
usrAuth: function() {
m.route(document.body, "/", {
"/": { view: () => m("p", "hello")}
})
},
usrNotAuth: function() {
m.route(document.body, "/", {
"/": { render: v => m(WelcomePage, eventbus) }
})
},
oninit: function(vnode) {
vnode.state.user = new User();
eventbus.subscribe({
type: "login",
handle: function(action) {
vnode.state.user.token = action.token;
console.log(JSON.stringify(vnode.state.user));
}
});
},
view: function(vnode) {
if(vnode.state.user.token) {
this.usrAuth();
} else {
this.usrNotAuth();
}
}
}
};
m.mount(document.body, MyApp);
MyApp is the main component. It check if user has a token, then return the proper route. This is the component that is in charge to let users login:
const m = require("mithril");
const hellojs = require("hellojs");
function TopBar(node) {
var bus = node.attrs.eventbus;
function _login() {
hellojs('facebook').login({scope:'email'});
}
return {
oninit: function(vnode) {
hellojs.init({
facebook: XXXXXXX,
}, {
redirect_uri: 'http://localhost'
});
hellojs.on('auth.login', auth => {
var fbtoken = auth.authResponse.access_token;
m.request({
method:"POST",
url:"./myapp/login/fb/token",
data:auth.authResponse,
background: true
}).then(function(result){
console.log(result);
bus.publish({ type: "login", token: result.jwttoken });
m.route.set("/");
}, function(error){
console.log(error);
bus.publish({ type: "login", token: "" });
});
});
},
view: function(vnode) {
return m("div", [
m("button", { onclick: _login }, "Login")
]);
}
}
}
export default TopBar;
TopBar component occurs in the WelcomePage component mentioned in the main one. TopBar renders a button and use hello.js to login. It uses the EventBus bus parameter to tell main component user logged in (there is an handler in main component to update the user model). Once user logins, event is fired and main component updates the user model. Good. Now, how can trigger the main component to load the right route?
I read mithril'docs again and I found that RouteResolvers perfectly suit my needs. Here is an example:
var App = (function() {
var login;
function isLoggedIn(component) {
if(login) {
return component;
} else {
m.route.set("/hey");
}
}
return {
oninit: function(vnode) {
EventBus.subscribe({
type: "login",
handle: function(action) {
console.log("incoming action: " + JSON.stringify(action));
login = action.value;
}
});
},
oncreate: function(vnode) {
Foo.eventbus = EventBus;
Bar.eventbus = EventBus;
Hey.eventbus = EventBus;
m.route(document.body, "/hey", {
"/foo": {
onmatch: function(args, requestedPath, route) { return isLoggedIn(Foo); }
},
"/bar": {
onmatch: function(args, requestedPath, route) { return isLoggedIn(Bar); }
},
"/hey": Hey
});
},
view: function(vnode) {
return m("div", "home..");
}
};
})();
Eventbus is used to let components communicate with App. They fire events (login type events) that App can handle. I found convenient to pass Eventbus the way oncreate method shows, I can use Eventbus in each component's oncreate to let components fire events.
I've got
<component-one></component-one>
<component-two></component-two>
<component-three></component-three>
Component two contains component three.
Currently I emit an event in <component-one> that has to be caught in <component-three>.
In <component-one> I fire the event like this:
this.$bus.$emit('setSecondBanner', finalBanner);
Then in <component-three> I catch it like this:
mounted() {
this.$bus.$on('setSecondBanner', (banner) => {
alert('Caught');
this.banner = banner;
});
},
But the event is never caught!
I define the bus like this (in my core.js):
let eventBus = new Vue();
Object.defineProperties(Vue.prototype, {
$bus: {
get: () => { return eventBus; }
}
});
What could be wrong here? When I check vue-dev-tools I can see that the event has fired!
This is the working example for vue1.
Object.defineProperty(Vue.prototype, '$bus', {
get() {
return this.$root.bus;
}
});
Vue.component('third', {
template: `<div> Third : {{ data }} </div>`,
props:['data']
});
Vue.component('second', {
template: `<div>Second component <third :data="data"></third></div>`,
ready() {
this.$bus.$on('setSecondBanner', (event) => {
this.data = event.data;
});
},
data() {
return {
data: 'Defautl value in second'
}
}
});
Vue.component('first', {
template: `<div>{{ data }}</div>`,
ready() {
setInterval(() => {
this.$bus.$emit('setSecondBanner', {
data: 'Bus sending some data : '+new Date(),
});
}, 1000);
},
data() {
return {
data: 'Defautl value in first'
}
}
});
var bus = new Vue({});
new Vue({
el: '#app',
data: {
bus: bus
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.js"></script>
<div id="app">
<second></second>
<first></first>
</div>
Have you tried registering the listener in created instead of mounted?
Also, why define the bus with defineProperties and not simply:
Vue.prototype.$bus = new Vue();
I am unable to catch the flash event on my custom component that i am emitting from the console . Here is my component:
/* file flash.vue */
<template>
<span :class="type" class="alert flash-alert" v-show="show">
{{ body }}
</span>
</template>
<script>
export default {
props: ['type','message'],
data() {
return {
body: this.message,
show: false,
};
},
created() {
if(this.body)
{
this.showComp();
this.hide();
}
},
methods: {
showComp: function(){
this.show = true;
},
hide: function()
{
var vm = this;
setTimeout(function() {
vm.show = false;
},2000);
},
},
events: {
flash: function(newMessage) {
this.body = newMessage;
this.showComp();
},
}
}
on the chrome console i am firing the event with:
/* from console */
window.vueEventBus = new Vue();
window.vueEventBus.$emit('flash','my message');
the event is firing as i can see that on the vue devtools tab. But upon catching the event the component should become visible, which is not.
However, if i piggyback the listener on the global event bus inside the components created() method, it works.
created() {
window.vueMessageBus.$on('flash',newMessage => {
this.body = newMessage;
this.showComp();
});
}
What should i do if i want the event listener to be registered inside the events property of the component itself?
-Thanks, Yeasir
look this example
eventbus created in index.js
Vue.prototype.$vueEventBus = new Vue()
listener on (see components/eventBus/eventBus.vue)
created() {
this.$vueEventBus.$on('message-in', this.newMessage)
},
beforeDestroy() {
this.$vueEventBus.$off('message-in')
}
emit event (see components/eventBus/childEventBus.vue)
methods: {
newMessage(something) {
this.$vueEventBus.$emit('message-in', something)
}
}
app page https://3xyx386q65.codesandbox.io/eventBus
Given:
<parent-element>
<sibling-a></sibling-a>
<sibling-b></sibling-b>
</parent-element>
How can I get access to a click event on a button in siblingA to change some value to another in sibling-b using $emit(…)?
#craig_h is correct, or you can use $refs like:
<parent-element>
<sibling-a #onClickButton="changeCall"></sibling-a>
<sibling-b ref="b"></sibling-b>
</parent-element>
In parent methods:
methods: {
changeCall() {
this.$refs.b.dataChange = 'changed';
}
}
In siblingA:
Vue.component('sibling-a', {
template: `<div><button #click="clickMe">Click Me</button></div>`,
methods: {
clickMe() {
this.$emit('onClickButton');
}
}
});
In siblingB:
Vue.component('sibling-b', {
template: `<div>{{dataChange}}</div>`,
data() {
return {
dataChange: 'no change'
}
}
});
For that you can simply use a global bus and emit your events on to that:
var bus = new Vue();
Vue.component('comp-a', {
template: `<div><button #click="emitFoo">Click Me</button></div>`,
methods: {
emitFoo() {
bus.$emit('foo');
}
}
});
Vue.component('comp-b', {
template: `<div>{{msg}}</div>`,
created() {
bus.$on('foo', () => {
this.msg = "Got Foo!";
})
},
data() {
return {
msg: 'comp-b'
}
}
});
Here's the JSFiddle: https://jsfiddle.net/6ekomf2c/
If you need to do anything more complicated then you should look at Vuex