Event callback function out of scope - javascript

I am struggling with events a little bit. I want class A to fire an event and class B shall catch that event and pass the event data to its own method:
class ClassA {
constructor() {
window.addEventListener("fire", function (e) { this.fired(e.detail); }); //<--- not working
}
fired(data) {
console.log("fired by: "+data);
}
}
class ClassB {
constructor() {
var event = new CustomEvent("fire", { detail: { data: "John Doe" } } );
window.dispatchEvent(event);
console.log("fired");
}
}
new ClassA(); //adds event listener
new ClassB(); //event dispatch

It looks like the scope of this does not refer to the class. You can use an arrow function instead in your ClassA:
window.addEventListener("fire", (e) => { this.fired(e.detail); })

Related

remove event listener in reactJS

I wants to remove event listener that are already in event listener.My Code is
public componentDidMount() {
this.drags();
}
private drags(){
const e = ReactDOM.findDOMNode(this.container);
if (e) {
e.addEventListener("mousedown", (event: any) => {
....
parent = ReactDOM.findDOMNode(this).parentNode;
if (parent) {
parent.addEventListener("mousemove", (event1: any) => {
....
const eDrag = parent.getElementsByClassName("draggable");
eRes[0].addEventListener("mouseup", (event3: any) => {
**// HERE I WANT TO REMOVE LISTENER OF PARENT OF MOUSE MOVE**
}
}
}
}
}
}
Can anybody help me in this ?
Do not use anonymous function as the event handler, use a named function instead.
So, if you add the listener this way:
function doSomething() {
// something
}
window.addEventListener('mousedown', this.doSomething);
You can remove it like:
window.removeEventListener('mousedown', this.doSomething);

Executing a callback one time after a function and its super functions have finished execution

I'm trying to execute a callback after a function and its super functions have finished execution.
It's important that:
The callback is executed only once
The callback is executed synchronously
The class methods are called in the provided order
The callback be specified one time, and not passed every time the function is called. The goal here is to provide event-listener style functionality
Given the following example:
class Car {
constructor(props) {
this.props = props;
}
brake() {
this.activateBrakes();
}
activateBrakes() {
console.log('1');
}
}
class Prius extends Car {
brake() {
super.brake();
this.activateRegenerativeBrakingSystem();
}
activateRegenerativeBrakingSystem() {
console.log('2');
}
}
var onBrake = () => console.log('after');
var car = new Car({onBrake});
car.brake();
var prius = new Prius({onBrake});
prius.brake();
https://jsfiddle.net/pL4jzcwv/20/
How can I get the console to print:
"1"
"after"
"1"
"2"
"after"
I'm not calling onBrake because, as far as I can tell, there’s nowhere it can be put, as-is, to make the console log what is described.
I can think of two ways to do this:
1. Make the implementation of braking separate from the method brake, and have Car's brake call the callback.
class Car {
// ...
brake() {
this.brakeImplementation(); // <==
this.props.onBrake(); // <==
}
brakeImplementation() { // <==
this.activateBrakes(); // <==
} // <==
// ...
}
(And Prius overrides brakeImplementation, not brake.)
Live Example:
class Car {
constructor(props) {
this.props = props;
}
brake() {
this.brakeImplementation();
this.props.onBrake();
}
brakeImplementation() {
this.activateBrakes();
}
activateBrakes() {
console.log('1');
}
}
class Prius extends Car {
brakeImplementation() {
super.brakeImplementation();
this.activateRegenerativeBrakingSystem();
}
activateRegenerativeBrakingSystem() {
console.log('2');
}
}
var onBrake = () => console.log('after');
var car = new Car({onBrake});
car.brake();
var prius = new Prius({onBrake});
prius.brake();
2. Have a method, say doneBraking, which accepts a constructor and only calls the callback if the constructor passed in is the constructor of the instance:
doneBraking(ctor) {
if (ctor === this.constructor) {
this.props.onBrake();
}
}
Then put a call to it at the end of brake in every class:
class Car {
// ...
brake() {
this.activateBrakes();
this.doneBraking(Car); // <==
}
// ...
}
class Prius extends Car {
// ...
brake() {
super.brake();
this.activateRegenerativeBrakingSystem();
this.doneBraking(Prius); // <==
}
// ...
}
A bit ugly, but... :-) Live Example:
class Car {
constructor(props) {
this.props = props;
}
brake() {
this.activateBrakes();
this.doneBraking(Car);
}
activateBrakes() {
console.log('1');
}
doneBraking(ctor) {
if (ctor === this.constructor) {
this.props.onBrake();
}
}
}
class Prius extends Car {
brake() {
super.brake();
this.activateRegenerativeBrakingSystem();
this.doneBraking(Prius);
}
activateRegenerativeBrakingSystem() {
console.log('2');
}
}
var onBrake = () => console.log('after');
var car = new Car({onBrake});
car.brake();
var prius = new Prius({onBrake});
prius.brake();
May be I misunderstood you but you mentioned event loops and I came with idea to push your callback onBrake to event loop as a next io task (process.nextTick), then it is possible to implement the idea with async functions.
The following example will work only in node.js.
class Emitter {
constructor(props) {
this.events = []
}
add(event) {
if (!this.events.includes(event.name)) {
this.events.push(event.name)
process.nextTick(event)
}
}
remove(event) {
this.events = this.events.filter(name => name !== event.name)
}
}
class Car {
constructor(props) {
this.props = props
this.event = new Emitter()
}
async brake() {
this.activateBrakes()
this.onBrake()
}
activateBrakes() {
console.log(1)
}
async onBrake () {
this.event.add(this.props.onBrake)
}
}
class Prius extends Car {
async brake() {
super.brake()
this.activateRegenerAtiveBrakingSystem()
this.onBrake()
}
activateRegenerAtiveBrakingSystem() {
console.log(2)
}
drive() {
this.event.add(() => console.log(`🚓 drive`))
}
}
const onBrake = () => console.log(`✋ stop`)
async function main() {
const car = new Car({onBrake})
await car.brake()
const prius = new Prius({onBrake})
prius.brake()
prius.drive()
}
main()
output

Cant bind eventlistener in es6 module syntax

I am fairly new to es6, but want to recreate my jQuery code into clean es6 modules (one file per module) and drop jQuery at all. But I am already lost by binding a simple eventhandler to my buttons.
This is my currently button.js file:
import forEach from 'lodash/forEach';
export default class Buttons {
constructor(root) {
console.log('constructor hello');
this.root = document.body;
this.buttons = this.root.querySelectorAll('.default-button');
this.bind();
}
bind() {
console.log('bind hello');
forEach(this.buttons, (button) => {
button.addEventListener('click', () => {
console.log('Click event just for test purpose');
})
})
}
}
Here is my main.js file
class sitemodules {
constructor() {
sitemodules.domReady().then(this.ready.bind(this));
}
ready() {
this.initButtons();
}
initButtons() {
new Buttons();
}
static domReady() {
return new Promise((resolve) => {
document.addEventListener('DOMContentLoaded', resolve);
});
}
}
new sitemodules();
'constructor hello' and 'bind hello' are fired in the console, but I can't get the message I implemented with the click listener, thus the eventlistener seems not to be added properly.

Is there any EventEmitter in browser side that has similar logic in NodeJS?

It is so easy to use eventEmitter in node.js:
var e = new EventEmitter();
e.on('happy', function(){console.log('good')});
e.emit('happy');
Any client side EventEmitter in browser native?
In modern browsers, there is EventTarget.
class MyClass extends EventTarget {
doSomething() {
this.dispatchEvent(new Event('something'));
}
}
const instance = new MyClass();
instance.addEventListener('something', (e) => {
console.log('Instance fired "something".', e);
});
instance.doSomething();
Additional Resources:
Maga Zandaqo has an excellent detailed guide here: https://medium.com/#zandaqo/eventtarget-the-future-of-javascript-event-systems-205ae32f5e6b
MDN has some documentation: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
Polyfill for Safari and other incapable browsers: https://github.com/ungap/event-target
There is a NPM package named "events" which makes you able to make event emitters in a browser environment.
const EventEmitter = require('events')
const e = new EventEmitter()
e.on('message', function (text) {
console.log(text)
})
e.emit('message', 'hello world')
in your case, it's
const EventEmitter = require('events')
const e = new EventEmitter();
e.on('happy', function() {
console.log('good');
});
e.emit('happy');
This is enough for given case.
class EventEmitter{
constructor(){
this.callbacks = {}
}
on(event, cb){
if(!this.callbacks[event]) this.callbacks[event] = [];
this.callbacks[event].push(cb)
}
emit(event, data){
let cbs = this.callbacks[event]
if(cbs){
cbs.forEach(cb => cb(data))
}
}
}
Update:
I just published little bit more evolved version of it. It is very simple yet probably enough:
https://www.npmjs.com/package/alpeventemitter
Create a customized event in the client, and attach to dom element:
var event = new Event('my-event');
// Listen for the event.
elem.addEventListener('my-event', function (e) { /* ... */ }, false);
// Dispatch the event.
elem.dispatchEvent(event);
This is referred from: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
Thanks Naeem Shaikh
I ended up using this:
export let createEventEmitter = () => {
let callbackList: (() => any)[] = []
return {
on(callback: () => any) {
callbackList.push(callback)
},
emit() {
callbackList.forEach((callback) => {
callback()
})
},
}
}
2022 update: The BroadcatsChannel may provide a solution.
https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API
I like the answer from Alparslan above. Here's one that uses the browser CustomEvent.
let EventEmitter = (function () {
let elem = document.createElement("div")
return {
on: function (name, cb) {
elem.addEventListener(name, (e) => cb(e.detail), false )
},
emit: function (name, data) {
elem.dispatchEvent(new CustomEvent(name, {detail: data}))
}
}
})()
I have created an npm package that do the same. You can use in Javascript or Typescript
event-emitter
Example
import { EventEmitter } from 'tahasoft-event-emitter';
const onStatusChange = new EventEmitter();
function updateStatus() {
// ...
onStatusChange.emit();
}
// somewhere else, we want to add a listener when status change
onStatusChange.add(() => {
// ...
});
Node gained a native EventTarget in Node 15 (Oct 2020;) this question no longer applies
https://nodejs.org/api/events.html#eventtarget-and-event-api
You need a JavaScript library, like this https://github.com/Olical/EventEmitter?

Is it possible to use Mutation Observer with a Three js element - A-Frame?

export class ColliderComponent {
constructor() {
this.observer = this.mutationObserver();
this.aframe();
}
//Registers the AFRAME component.
aframe(){
const __this = this;
AFRAME.registerComponent('collider', {
schema: {
},
init: function () {
console.log("The element to be observed is:",this.el);
__this.observer.observe(this.el, {characterData:true, subtree:true, attributes: true, attributeFilter: ['position'], childList : true});
},
tick : function(){
console.log(this.el.getObject3D('mesh').position);
}
});
}
private tick(){
}
private mutationObserver() : MutationObserver{
return new MutationObserver(mutations => {
mutations.forEach(mutation => {
console.log("Changed position");
});
});
}
}
I'm working on creating a simple collider. I'm going to track the elements that have the "collider" component and check if they're intersecting using intersectsBox. Unfortunately, I can't seem to make the MutationObserver to work. I'd rather use this approach instead of the tick, because it will start executing it per frame, instead when the elements move.
Any suggestions?
You can use
el.addEventListener('componentchanged', function (evt) {
if (evt.detail.name === 'position') {
}
});
But polling/ticking via tick is synchronous and probably still not a bad way to go.

Categories