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);
Related
i am using v-click-outside and want to pass value to the function but i am having error
This is how i am passing a value
Here is my code from Main.js file
vue_app.directive('click-outside', {
beforeMount(el, binding, vnode) {
el.clickOutsideEvent = evt => {
evt.stopPropagation()
if (!(el === evt.target || el.contains(evt.target))) {
binding.value(evt, el)
}
}
// Wait 1 frame otherwise a potential click that mounted the element will immediately trigger a click-outside event:
window.requestAnimationFrame(() => {
document.addEventListener('click', el.clickOutsideEvent)
})
},
unmounted(el) {
document.removeEventListener('click', el.clickOutsideEvent)
},
});
You have to pass a function to the directive, but right now you call it right away and pass the returned value. So instead of
v-click-outside="hideAllShowDetailDropdown(show.show_ID)"
Try this:
v-click-outside="() => hideAllShowDetailDropdown(show.show_ID)"
I've created a custom hook within my React app, but for some reason when I update the internal state via an event listener, it causes an infinite loop to be triggered (when it shouldn't). Here's my code:
// Note that this isn't a React component - just a regular JavaScript class.
class Player{
static #audio = new Audio();
static #listenersStarted = false;
static #listenerCallbacks = {
playing: [],
paused: [],
loaded: []
};
static mount(){
const loaded = () => {
this.removeListenerCallback("loaded", loaded);
};
this.addListenerCallback("loaded", loaded);
}
// This method is called on the initialization of the React
// app and is only called once. It's only purpose is to ensure
// that all of the listeners and their callbacks get fired.
static startListeners(){
const eventShorthands = {
playing: "play playing",
paused: "pause ended",
loaded: "loadedmetadata"
};
Object.keys(eventShorthands).forEach(key => {
const actualEvents = eventShorthands[key];
actualEvents.split(" ").forEach(actualEvent => {
this.#audio.addEventListener(actualEvent, e => {
const callbacks = this.#listenerCallbacks[key];
callbacks.forEach(callback => {
callback(e)
});
});
});
});
}
static addListenerCallback(event, callback){
const callbacks = this.#listenerCallbacks;
if(callbacks.hasOwnProperty(event)){
// Remember this console log
console.log(true);
this.#listenerCallbacks[event].push(callback);
}
}
static removeListenerCallback(event, callback){
const listenerCallbacks = this.#listenerCallbacks;
if(listenerCallbacks.hasOwnProperty(event)){
const index = listenerCallbacks[event].indexOf(callback);
this.#listenerCallbacks[event].splice(index, 1);
}
}
}
const usePlayer = (slug) => {
// State setup
const [state, setState] = useReducer(
(state, newState) => ({ ...state, ...newState }), {
mounted: false,
animationRunning: false,
allowNextFrame: false
}
);
const _handleLoadedMetadata = () => {
// If I remove this _stopAnimation, the console log mentioned
// in the player class only logs true to the console 5 times.
// Whereas if I keep it, it will log true infinitely.
_stopAnimation();
};
const _stopAnimation = () => {
setState({
allowNextFrame: false,
animationRunning: false
});
}
useEffect(() => {
Player.addListenerCallback("loaded", _handleLoadedMetadata);
return () => {
Player.removeListenerCallback("loaded", _handleLoadedMetadata);
};
}, []);
return {
mounted: state.mounted
};
};
This makes me think that the component keeps on re-rendering and calling Player.addListenerCallback(), but the strange thing is, if I put a console.log(true) within the useEffect() at the end, it'll only output it twice.
All help is appreciated, cheers.
When you're hooking (pun unintended) up inner functions in React components (or hooks) to external event handlers, you'll want to be mindful of the fact that the inner function's identity changes on every render unless you use useCallback() (which is a specialization of useMemo) to guide React to keep a reference to it between renders.
Here's a small simplification/refactoring of your code that seems to work with no infinite loops.
instead of a class with only static members, Player is a regular class of which there is an app-wide singletonesque instance.
instead of hooking up separate event listeners for each event, the often-overlooked handleEvent protocol for addEventListener is used
the hook event listener callback is now properly useCallbacked.
the hook event listener callback is responsible for looking at the event.type field to figure out what's happening.
the useEffect now properly has the ref to the callback it registers/unregisters, so if the identity of the callback does change, it gets properly re-registered.
I wasn't sure what the state in your hook was used for, so it's not here (but I'd recommend three separate state atoms instead of (ab)using useDispatch for an object state if possible).
The same code is here in a Codesandbox (with a base64-encoded example mp3 that I didn't care to add here for brevity).
const SMALL_MP3 = "https://...";
class Player {
#audio = new Audio();
#eventListeners = [];
constructor() {
["play", "playing", "pause", "ended", "loadedmetadata", "canplay"].forEach((event) => {
this.#audio.addEventListener(event, this);
});
}
play(src) {
if (!this.#audio.parentNode) {
document.body.appendChild(this.#audio);
}
this.#audio.src = src;
}
handleEvent = (event) => {
this.#eventListeners.forEach((listener) => listener(event));
};
addListenerCallback(callback) {
this.#eventListeners.push(callback);
}
removeListenerCallback(callback) {
this.#eventListeners = this.#eventListeners.filter((c) => c !== callback);
}
}
const player = new Player();
const usePlayer = (slug) => {
const eventHandler = React.useCallback(
(event) => {
console.log("slug:", slug, "event:", event.type);
},
[slug],
);
React.useEffect(() => {
player.addListenerCallback(eventHandler);
return () => player.removeListenerCallback(eventHandler);
}, [eventHandler]);
};
export default function App() {
usePlayer("floop");
const handlePlay = React.useCallback(() => {
player.play(SMALL_MP3);
}, []);
return (
<div className="App">
<button onClick={handlePlay}>Set player source</button>
</div>
);
}
The output, when one clicks on the button, is
slug: floop event: loadedmetadata
slug: floop event: canplay
I need to use navigator.sendBeacon() on window unload in order to let my server know the client has closed his window. I have searched everywhere and it just doesn't work for me.
For reference, the solution in this post didn't work either.
I have an App component that wraps my entire project. I am trying to set the unload event on it's componentDidMount() lifecycle method, and it just won't fire.
componentDidMount() {
window.addEventListener("beforeunload", this.unload);
}
componentWillUnmount() {
window.addEventListener("beforeunload", this.unload);
}
unload(e) {
e.preventDefault();
e.returnValue = 'test';
navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`);
return 'test';
}
I expect the server to get the AJAX call, and the window to prompt the user 'test' before the window is closed. What actually happens is the window just closes as usual.
NOTE: the return 'test' & e.returnValue = '' statements are purely for testing. I'm only interested in the AJAX request.
Any help would be much appreciated.
If you're using a functional component, you can try this:
useEffect(() => {
window.addEventListener("beforeunload", handleUnload);
return () => {
window.removeEventListener("beforeunload", handleUnload);
};
}, []);
const handleUnload = (e) => {
const message = "o/";
(e || window.event).returnValue = message; //Gecko + IE
return message;
};
You should bind this to the unload method or transform it to arrow function.
Binging way
constructor() {
super();
this.state = {
//stuff
};
this.unload.bind(this);
}
componentDidMount() {
window.addEventListener("beforeunload", this.unload);
}
componentWillUnmount() {
window.removeEventListener("beforeunload", this.unload);
}
unload(e) {
navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`);
}
Arrow functions way:
constructor() {
super();
this.state = {
//stuff
};
}
componentDidMount() {
window.addEventListener("beforeunload", this.unload);
}
componentWillUnmount() {
window.removeEventListener("beforeunload", this.unload);
}
unload = (e) => {
navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`);
}
Remember to remove the eventlistener on componentWillUnmount (you are currently adding it again).
You may be able to use navigator.sendBeacon.
const UnloadBeacon = ({
url,
payload = () => {},
children
}) => {
const eventHandler = () => navigator.sendBeacon(url, payload())
useEffect(() => {
window.addEventListener('unload', eventHandler, true)
return () => {
window.removeEventListener('unload', eventHandler, true)
}
}, [])
return children
}
full example here: https://gist.github.com/tmarshall/b5433a2c2acd5dbfc592bbc4dd4c519c
Have you tried declaring upload function as a fat arrow function? Also declare it before componentDidMount. (for better readability) before passing it as a reference.
Also have you tried attaching listener in contructor ? And make surw to bind your function in constructor. For reference
Also destroy the listener at componentWillUnmount, instead of adding it. (useless) use reference to listener, to destroy. Which you will create in constructor.
Best of luck
I am unsure why beforeunload is not working, but as a workaround, you may consider using the hashchange event.
componentDidMount() {
window.addEventListener("hashchange", this.doSomething, false);
}
componentWillUnmount() {
window.removeEventListener("hashchange", this.doSomething, false);
}
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.
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); })