Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
160
rated 0 times [  167] [ 7]  / answers: 1 / hits: 10132  / 4 Years ago, mon, may 18, 2020, 12:00:00

I am working on a vue project and want to emit an event from a child component to a parent component after some time span (user hovers over element, and after a few seconds, the emit should happen).



I am pretty sure I have done emits similar to this in other components and that it has worked before, but now I get these two errors. I am not sure what has changed. I implemented vuex after my first try, came back to this and now I am not sure what happend? But maybe I just deleted something or I don't know.
I also tried a console log just above the line that seems problematic and there the this value doesn't seem to be null.
These are the errors I get:



[Vue warn]: Error in v-on handler: TypeError: Cannot read property 'emit' of null and after that the error Cannot read property 'emit' of null The first error mentions, that the error was found in the component, shown beneath.



Most stuff I saw related to this problem was about people doing es6 arrow functions incorrectly, so maybe the this.timer = setInterval(() => this.countdown(), 1000);is problematic? I am not quite sure.



And here is the component (please excuse the messy code):



<template>
<div
:id=id
class=board
@dragenter.prevent
@dragover.prevent
@drop.prevent=drop
@dragenter=dragenter($event)
@dragover=dragover($event)
@dragleave=dragleave($event)
>
<slot class=row/>
<div
:id=`ui-details-${id}`
v-show=extendedHover>
Long hover
</div>
</div>
</template>

<script>
export default {
name: 'Devices',
props: ['id', 'acceptsDrop'],
data() {
return {
extendedHover: false,
timer: null,
totalTime: 2,
};
},
methods: {
drop(e) {
if (e.dataTransfer.getData('type') === 'layout') { // only accept dropped cards, not boards
const layoutId = e.dataTransfer.getData('layout_id');
this.$emit('dropped-layout', layoutId);
}
clearInterval(this.timer);
this.timer = null;
this.totalTime = 2;
console.log(e.dataTransfer.getData('card_id'));
e.target.classList.remove('hover-drag-over');
this.extendedHover = false;
// this.$emit('cancel-hover');
console.log('-------------dropped');
console.log(e);
console.log(e.dataTransfer.getData('type'));
/* const cardId = e.dataTransfer.getData('card_id');
console.warn('dropped onto device');
this.$emit('dropped-component', cardId);
e.target.classList.remove('hover-drag-over'); */
},
dragenter(e) {
// on dragenter we start a countdown of 1s
// over this value --> we see it as a long hover
console.log('------------dragenter');
console.log(e);
this.timer = setInterval(() => this.countdown(), 1000);
},
dragover(e) {
if (this.acceptsDrop) {
e.target.classList.add('hover-drag-over');
}
},
dragleave(e) {
if (this.acceptsDrop) {
clearInterval(this.timer);
this.timer = null;
this.totalTime = 2;
e.target.classList.remove('hover-drag-over');
this.extendedHover = false;
// this.$emit('cancel-hover');
}
},
countdown() {
this.totalTime -= 1;
if (this.totalTime === 0) {
this.extendedHover = true;
console.warn(this);
this.$emit('long-hover'); //this is the problematic line
}
},
},
};
</script>

<style scoped>
.board{
width: 100%;
min-height: 200px;
}
</style>


Thanks for any help!



Edit:
the output of the console.log is the following VueComponent {_uid: 18, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} there is some possibility to extend for more information if it is needed too.



Edit2: this component gets generated depending on an array in the parent component like this. So the slot only gets filled with a string for now.



<div
class = col-4
v-for=(device, index) in devices
v-bind:key=`device-${device.ip}`
>
<Devices
:id=`board-${device.ip}`
v-bind:class={'droparea-device':true, 'your-device': (index === thisDeviceIndex)}
@dropped-layout=$emit('dropped-layout', $event, index)
@long-hover=fetchAvailableUIsForDevice(device.device_name)
@cancel-hover=cancelHover()
:acceptsDrop=true
>
{{device.device_name}}
</Devices>
</div>


Edit3:
For testing I also just wanted to try a very basic thing. So I added a Button with an on click event like this (but still there are errors):



 <b-button
type=button
variant=success
v-on:click=$emit('long-hover')
>
Control Center
</b-button>

More From » vue.js

 Answers
7

So thanks for your help witih this strange behavior. After testing the emit with a button and it still not working, I thought that this was very suspicious.
Just to make sure, I took a look into the parent component because there I execute a function when the child emits the event.
When I looked into the function, I had the following line:



this.socket.emit('fetch_available_uis', { device_name: device });


And here the error description fitted! Because as I said, I included Vuex and after that it didn't work anymore. When adding vuex, I also moved the socket connection to the store so now there was indeed no this.socket or better to say the null value that was mentioned above.
I fixed this line and the error now is gone!



So for others with similar problems in the future, I recommend to look at functions in parents that receive your childs event and check for mistakes there. Because even though the error was in the parent, the error messages still showed that the error was found in the child probably because it took the component where the event was emitted as the source and not the component above.


[#3774] Friday, May 15, 2020, 4 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
brennanm

Total Points: 510
Total Questions: 103
Total Answers: 95

Location: Nicaragua
Member since Tue, Dec 8, 2020
4 Years ago
brennanm questions
Thu, Jan 9, 20, 00:00, 5 Years ago
Thu, Sep 26, 19, 00:00, 5 Years ago
Thu, Aug 29, 19, 00:00, 5 Years ago
Thu, Aug 15, 19, 00:00, 5 Years ago
;