How do I let the event know that I'm needing to pass in 3 parameters to the handle method of my event.
config/web.php
'on eventname' => [EventName::class, 'handle'],
app/events/EventName.php
namespace app\events;
class EventName
{
public function handle($arg1, $arg2, $arg3)
{
}
}
Signature of your event handler is incorrect. Event handler takes only one argument - event object. If you need to pass three arguments to handler, you need to create custom event object and use its arguments to store these values.
Create custom event:
class MyEvent extends \yii\base\Event {
public $arg1;
public $arg2;
public $arg3;
}
Use it on event trigger:
$this->trigger('eventname', new MyEvent([
'arg1' => $arg1,
'arg2' => $arg2,
'arg3' => $arg3,
]));
And use event properties in handler:
public function handle(MyEvent $event) {
if ($event->arg1) {
// ...
}
}
Related
I want to write a component set out of HTML elements. For example:
export default class Control implements EventTarget {
// parent control, not HTML "parentElement"
parent: Control | null;
private _events: Map<string, EventListener[]> = new Map;
// addEventListener(...) {}
// removeEventListener(...) {}
// dispatchEvent(...) {}
}
Subtype:
export default class TabBar extends Control {
// ...
}
So I'd implement EventTarget and any events would be subtype of the standard DOM's Event type. However, I want to support proper event propagation, both capture and bubbling phases.
The problem is, if I implement the standard DOM's EventTarget type, I must also use the standard DOM's Event type. It's a problem because I'm unable to set the value of event.target, event.currentTarget and event.eventPhase: see the constructor at www.developer.mozilla.org.
One solution is for me to reinvent Event, and consequently reinvent EventTarget, but this would lead to duplicate code and lead to ambiguity. Is there anything I missing?
Another solution is to mix HTML and my component set, where my set will use simple event listening properties, like onchange: ((d: EventData) => void) | null.
It seems not possible to mutate properties like target, eventPhase and so on, which led me to create a small package for constructing your own event listeners where these properties are mutable. Also, you can use TypeScript generics to allow mapping event type (for example, 'mouseover') to event data type (MouseEvent):
import { EventTarget, EventRegistry, Event, } from 'byo-event-system';
interface EventHandlersEventMap {
"someevent": RegExp; // listener takes a RegExp
"anotherevent": boolean; // listener takes a Boolean
}
export class MyType implements EventTarget {
private _eventRegistry = new EventRegistry;
addEventListener<E extends keyof EventHandlersEventMap>(type: E, listener: (evt: EventHandlersEventMap[E]) => void, useCapture: boolean = false): void {
this._eventRegistry.addEventListener(type, listener as ((evt: Event): void), useCapture);
}
removeEventListener<E extends keyof EventHandlersEventMap>(type: E, listener: (evt: EventHandlersEventMap[E]) => void): void {
this._eventRegistry.removeEventListener(type, listener as ((evt: Event): void));
}
dispatchEvent(event: Event): boolean {
return this._eventRegistry.dispatchEvent(event);
}
hasEventListener(type: string): boolean {
return this._eventRegistry.hasEventListener(type);
}
}
You can find it on www.npmjs.com.
Here is my Behavior's class events() method. When I trigger an event second handler i.e. sendMailHanlder gets called and it ignores anotherOne. I believe, the second one overwrites first one. How do I solve this problem so that both event handlers get called?
// UserBehavior.php
public function events()
{
return [
Users::EVENT_NEW_USER => [$this, 'anotherOne'],
Users::EVENT_NEW_USER => [$this, 'sendMailHanlder'],
];
}
// here are two handlers
public function sendMailHanlder($e)
{
echo ";
}
public function anotherOne($e)
{
echo 'another one';
}
One thing to notice is that I'm attaching this behavior to my Users.php model. I tried adding both handlers using model's init() method. That way both handlers got called. Here is my init code.
public function init()
{
$this->on(self::EVENT_NEW_USER, [$this, 'anotherOne']);
$this->on(self::EVENT_NEW_USER, [$this, 'sendMailHanlder']);
}
You can override Behavior::attach() so you can have something like this in your UserBehavior and no need of your events()
// UserBehavior.php
public function attach($owner)
{
parent::attach($owner);
$owner->on(self::EVENT_NEW_USER, [$this, 'anotherOne']);
$owner->on(self::EVENT_NEW_USER, [$this, 'sendMailHanlder']);
}
You can use anonymous function for attaching handler's in events method :
ActiveRecord::EVENT_AFTER_UPDATE => function ($event) {
$this->deleteRemovalRequestFiles();
$this->uploadFiles();
}
You should not use equal event names. Use this instead:
public function events()
{
return [
Users::EVENT_NEW_USER => [$this, 'sendMailHanlder'],
];
}
// Here are two handlers
public function sendMailHanlder($e)
{
echo '';
$this->anotherOne($e);
}
public function anotherOne($e)
{
echo 'another one';
}
Can any one give me a simple example on how to dispatch an event in actionscript3 with an object attached to it, like
dispatchEvent( new Event(GOT_RESULT,result));
Here result is an object that I want to pass along with the event.
In case you want to pass an object through an event you should create a custom event. The code should be something like this.
public class MyEvent extends Event
{
public static const GOT_RESULT:String = "gotResult";
// this is the object you want to pass through your event.
public var result:Object;
public function MyEvent(type:String, result:Object, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.result = result;
}
// always create a clone() method for events in case you want to redispatch them.
public override function clone():Event
{
return new MyEvent(type, result, bubbles, cancelable);
}
}
Then you can use the code above like this:
dispatchEvent(new MyEvent(MyEvent.GOT_RESULT, result));
And you listen for this event where necessary.
addEventListener(MyEvent.GOT_RESULT, myEventHandler);
// more code to follow here...
protected function myEventHandler(event:MyEvent):void
{
var myResult:Object = event.result; // this is how you use the event's property.
}
This post is a little old but if it can help someone, you can use DataEvent class like so:
dispatchEvent(new DataEvent(YOUR_EVENT_ID, true, false, data));
Documentation
If designed properly you shouldn't have to pass an object to the event.
Instead you should make a public var on the dispatching class.
public var myObject:Object;
// before you dispatch the event assign the object to your class var
myObject = ....// whatever it is your want to pass
// When you dispatch an event you can do it with already created events or like Tomislav wrote and create a custom class.
// in the call back just use currentTarget
public function myCallBackFunction(event:Event):void{
// typecast the event target object
var myClass:myClassThatDispatchedtheEvent = event.currentTarget as myClassThatDispatchedtheEvent
trace( myClass.myObject )// the object or var you want from the dispatching class.
Can anyone provide an example of how to write a callback instead of using an event to communicate between two classes (objects) in Actionscript 3.0?
Just pass a function to another one as parameter to make your callback :
class A {
function A(){
}
// function to be called when work is finished
private function workDone():void {
//...
}
public function foo():void {
var b:B=new B();
b.doWork(workDone); // pass the callback to the work function
//can also be an anonymous function, etc..
b.doWork(
function():void{
//....
}
);
}
}
class B {
function B(){
}
public function doWork(callback:Function):void{
// do my work
callback(); // call the callback function when necessary
}
}
What do you mean? A callback is a function that is called in response to an event - in AS parlance, it's an event listener. If you just want classes to communicate, have one of them call a method on the other.
I've created an Event Handler/Listener like so:
import flash.events.Event;
public class DanielEvent extends Event {
public var data:*;
public static const APP_STARTED:String = "APP_STARTED";
public function DanielEvent(n:String, data:*){
this.data = data;
super(n)
}
}
Listening to an event using:
addEventListener(DanielEvent.APP_STARTED, appStarted);
Dispatching an event by:
dispatchEvent(new DanielEvent("APP_STARTED", "test"))
And receiving the data by:
private function appStarted(e:Event){
trace(e.data)
}
But I get the error:
Access of possibly undefined property
data through a reference with static
type flash.events:Event.
You have to use your custom event type in the event handler, if you want to access the data property:
private function appStarted(e:DanielEvent): void {
trace(e.data);
}
your event handler is passed a DanielEvent, not an Event:
private function appStarted(e:DanielEvent):void
{
trace(e.data);
}
also. you should also use your constant for your dispatch instead of passing a string, like you've done for your listener:
dispatchEvent(new DanielEvent(DanielEvent.APP_STARTED, "test"));
and don't forget to override clone() if you are planning on dispatching that event more than once.
public override function clone():Event
{
return new DanielEvent(n, data);
}