How to Emit and Handle Custom Events

How to emit and handle custom events?

In general:

  1. Create a desired EventType.
  2. Create the corresponding Event.
  3. Call Node.fireEvent().
  4. Add Handlers and/or Filters for EventTypes of interest.

Some explanations:

If you want to create an event cascade, start with an "All" or "Any" type, that will be the root of all of the EventTypes:

EventType<MyEvent> OPTIONS_ALL = new EventType<>("OPTIONS_ALL");

This makes possible creating descendants of this type:

EventType<MyEvent> BEFORE_STORE = new EventType<>(OPTIONS_ALL, "BEFORE_STORE");

Then write the MyEvent class (which extends Event). The EventTypes should be typed to this event class (as is my example).

Now use (or in other words: fire) the event:

Event myEvent = new MyEvent();
Node node = ....;
node.fireEvent(myEvent);

If you want to catch this event:

Node node = ....;
node.addEventHandler(OPTIONS_ALL, event -> handle(...));
node.addEventHandler(BEFORE_STORE, event -> handle(...));

Emitting custom event in React

As @usafder, mentioned the way. I am just adding the basic callback function for an input field. So on the console you can see the current value.

Basically callback function is the way to get the data from the Child component.

Parent.js

import React from "react";
import Child from "./Child";

export default function App() {
const parentHandleChange = (e) => {
console.log(e.target.value);
};

return (
<div>
<Child handleChange={parentHandleChange} />
</div>
);
}

Child.js

import React from "react";

const Child = (props) => {
return <input onChange={props.handleChange} />;
};

export default Child;

Working codesandbox

Addition to it if you need return a custom value use like this

<Child onHandleChange={() => parentHandleChange(10)}

Because in this it won't call every-time if you want pass a value.

How to create and fire a custom event in angular

Of course, you can use an eventEmitter
in my-component ts file add this

 @Output() deleteItem= new EventEmitter();

and when you want to rise the event do this

  this.deleteItem.emit();

also you can pass data like this

  this.countUpdate.emit({value: some data });

then catch it in the parent component like this

<my-component (deleteItem)="doSomething($event)"></my-component>

and in the parent ts file

    doSomething(event)
{
console.log(event);
}

How to create and emit custom event with Combine and Swift?

Here is the solution utilising PassthroughSubject. For now the shortest and cleanest one I could produce. Tested with multiple subscribers, works like expected.

class MainClass {
private let sequenceManager: SequenceManager = .init()
private var bucket: Set<AnyCancellable> = []

func subscribeMe() {
//Here is how we use our publisher
sequenceManager
.publisher(for: .onSequenceUpdate)
.receive(on: DispatchQueue.main) //Optionally
.sink { (addingItems, removingItems) in
//Handle new data here
}
.store(in: &bucket)
}
}

//Object we want to publish its changes
class SequenceManager {
private let sequencePublisher = UpdatedSequencePublisher()

private func didUpdate(addingItems: [String], removingItems: [String]) {
//Here we publish changes
sequencePublisher.publish(adding: addingItems, removing: removingItems)
}
}

//Our publisher stuff
extension SequenceManager {
struct UpdatedSequencePublisher: Publisher {
typealias Output = (adding: [String], removing: [String])
typealias Failure = Never
private let passThroughSubject = PassthroughSubject<Output, Failure>()

func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
passThroughSubject.receive(subscriber: subscriber)
}

func publish(adding: [String], removing: [String]) {
passThroughSubject.send((adding, removing))
}
}

func publisher(for event: Event) -> UpdatedSequencePublisher {
switch event {
case .onSequenceUpdate:
return sequencePublisher
}
}

enum Event {
case onSequenceUpdate
}
}

how to add custom event handler?

You can listen for and emit events of any name on any event emitter. But unless you have some code which emits the event you are listening for, such as server.emit('event1', data), the listener won't be called.

Custom JavaFX events

You cannot. JavaFX uses javafx.event.Events or subtypes, so String or even primitive int can't be passed.

You could however create a custom subtype of Event and add the parameters to this class.

Similarly only classes implementing javafx.event.EventHandler can be registered as event handlers.

You could create a event handler class that delegates to your methods though:

public abstract class CustomEvent extends Event {

public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE = new EventType(ANY);

public CustomEvent(EventType<? extends Event> eventType) {
super(eventType);
}

public abstract void invokeHandler(MyCustomEventHandler handler);

}
public class CustomEvent1 extends CustomEvent {

public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE_1 = new EventType(CUSTOM_EVENT_TYPE, "CustomEvent1");

private final int param;

public CustomEvent1(int param) {
super(CUSTOM_EVENT_TYPE_1);
this.param = param;
}

@Override
public void invokeHandler(MyCustomEventHandler handler) {
handler.onEvent1(param);
}

}
public class CustomEvent2 extends CustomEvent {

public static final EventType<CustomEvent> CUSTOM_EVENT_TYPE_2 = new EventType(CUSTOM_EVENT_TYPE, "CustomEvent2");

private final String param;

public CustomEvent2(String param) {
super(CUSTOM_EVENT_TYPE_2);
this.param = param;
}

@Override
public void invokeHandler(MyCustomEventHandler handler) {
handler.onEvent2(param);
}

}
public abstract class MyCustomEventHandler implements EventHandler<CustomEvent> {

public abstract void onEvent1(int param0);

public abstract void onEvent2(String param0);

@Override
public void handle(CustomEvent event) {
event.invokeHandler(this);
}
}

Usage Example

Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
btn.fireEvent(new CustomEvent1(42));
btn.fireEvent(new CustomEvent2("Hello World"));
});

btn.addEventHandler(CustomEvent.CUSTOM_EVENT_TYPE, new MyCustomEventHandler() {

@Override
public void onEvent1(int param0) {
System.out.println("integer parameter: " + param0);
}

@Override
public void onEvent2(String param0) {
System.out.println("string parameter: "+param0);
}
});

Emitting a custom event within a function in methods object

Try with this

methods: {
updateRecipeClicked() {
this.$emit('update-recipe-clicked', this.newRecipe );
// some other code will be written here
}
},

How to emit custom Events to the Event Loop in PyQt

In PyQt the following instruction:

document.addEventListener('Hello', () => console.log('Got it'))

is equivalent

document.hello_signal.connect(lambda: print('Got it'))

In a similar way:

document.dispatchEvent(new Event("Hello"))

is equivalent

document.hello_signal.emit()

But the big difference is the scope of the "document" object, since the connection is between a global element. But in PyQt that element does not exist.

One way to emulate the behavior that you point out is by creating a global object:

globalobject.py

from PyQt5 import QtCore
import functools

@functools.lru_cache()
class GlobalObject(QtCore.QObject):
def __init__(self):
super().__init__()
self._events = {}

def addEventListener(self, name, func):
if name not in self._events:
self._events[name] = [func]
else:
self._events[name].append(func)

def dispatchEvent(self, name):
functions = self._events.get(name, [])
for func in functions:
QtCore.QTimer.singleShot(0, func)

main.py

from PyQt5 import QtCore, QtWidgets
from globalobject import GlobalObject

class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton(text="Press me", clicked=self.on_clicked)
self.setCentralWidget(button)

@QtCore.pyqtSlot()
def on_clicked(self):
GlobalObject().dispatchEvent("hello")

class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
GlobalObject().addEventListener("hello", self.foo)
self._label = QtWidgets.QLabel()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self._label)

@QtCore.pyqtSlot()
def foo(self):
self._label.setText("foo")

if __name__ == "__main__":
import sys

app = QtWidgets.QApplication(sys.argv)
w1 = MainWindow()
w2 = Widget()
w1.show()
w2.show()
sys.exit(app.exec_())

child component emit an custom event, but parent component's listener not triggered

The problem is that custom events should not be named with camelCase. If you look at the error message in the console, it tells you:

Event "itemadd" is emitted in component but the handler is registered for "itemAdd"

The component is emitting a lowercase version even though you've used camelCase to name it. Renaming to all lowercase or kebab-case will fix it.

In the parent template:

<add-item-component @itemadd="addAItem">

Emitting from the child:

this.$emit('itemadd');

This is discussed a bit with Evan You (Vue creator) here



Related Topics



Leave a reply



Submit