Posts Tagged ‘EventDispatcher’

[JavaScript] Observer pattern like EventDispatcher in AS3

Tuesday, November 29th, 2011

I made Observer pattern classes in JavaScript.
Here is code.

var kinkuma = {}; //package name
(function(pkg){
	pkg.Event = function(){
		this.target;
		this.context;
	};
	pkg.Observer = function(){
		this.listeners = {};
	};
	pkg.Observer.prototype = {
		addObserver:function(type, listener, context){
			var listeners = this.listeners;
			if(!listeners[type]){
				listeners[type] = [];
			}
			listeners[type].push([listener, context]);
		},
		removeObserver:function(type, listener){
			var listeners = this.listeners;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = len - 1; i >= 0; i--){
					var arr = listeners[type][i];
					if(arr[0] == listener){
						listeners[type].splice(i, 1);
					}
				}
			}
		},
		notify:function(type){
			var listeners = this.listeners;
			var e = new pkg.Event();
			e.target = this;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = 0; i < len; i++){
					var arr = listeners[type][i];
					e.context = arr[1];
					arr[0](e);
				}
			}
		}
	}
})(kinkuma);

Usage 1 simple

I made simple class.

var MyData = function(){
	this.change = function(){
		this.notify("CHANGE"); //trigger
	};
};
MyData.prototype = new kinkuma.Observer(); //extends Observer

function hello(){
	alert('hello');
}

var d = new MyData();
d.addObserver("CHANGE", hello); //linkage with hello function
d.change(); //let's try

Usage 2 With MVC pattern like in AS3

>> Would you try to do this page.

If you push button, mycar moves to right.
But if it is over 200px, it stops to move.

I used MVC pattern.

The code is here.

<html>
<head>
<meta charset="UTF-8" />
<script type="text/javascript" src="jquery-1.6.2.min.js"></script>
<script type="text/javascript">

var kinkuma = {}; //package name
(function(pkg){
	pkg.Event = function(){
		this.target;
		this.context;
	};
	pkg.Observer = function(){
		this.listeners = {};
	};
	pkg.Observer.prototype = {
		addObserver:function(type, listener, context){
			var listeners = this.listeners;
			if(!listeners[type]){
				listeners[type] = [];
			}
			listeners[type].push([listener, context]);
		},
		removeObserver:function(type, listener){
			var listeners = this.listeners;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = len - 1; i >= 0; i--){
					var arr = listeners[type][i];
					if(arr[0] == listener){
						listeners[type].splice(i, 1);
					}
				}
			}
		},
		notify:function(type){
			var listeners = this.listeners;
			var e = new pkg.Event();
			e.target = this;
			if(listeners[type]){
				var i;
				var len = listeners[type].length;
				for(i = 0; i < len; i++){
					var arr = listeners[type][i];
					e.context = arr[1];
					arr[0](e);
				}
			}
		}
	}
})(kinkuma);

function trace(str){
	console.log(str);
}

var DataEvent = {
	CHANGE:"change"
}

//Model
var CarData = function(){
	this.posX = 0;
};
CarData.prototype = new kinkuma.Observer();
CarData.prototype.setPosX = function(aPosX){
	this.posX = aPosX;
	this.notify(DataEvent.CHANGE);
};

//View
var CarView = function(data){
	this.cardata = data;
	this.view;
	this.cardata.addObserver(DataEvent.CHANGE, this.onCardataChange, this);
	this.createView();
};
CarView.prototype.createView = function(){
	$('body').append('<div id="carview" style="width:60px;height:30px;background-color:#aaa;position:absolute;top:100px;left:0px;font-size:12px;text-align:center;font-family:sans-serif">mycar</div>');
	this.view = $('#carview');
};
CarView.prototype.onCardataChange = function(e){
	var self = e.context; //CarView instance
	var data = e.target; //observer instance
	self.view.css({left:data.posX + 'px'});
	if(data.posX > 200){
		self.cardata.removeObserver(DataEvent.CHANGE, self.onCardataChange);
	}
};

//Main
var Main = function(){
	this.cardata;
	this.carView;
};
Main.prototype = {
	init:function(){
		var self = this;
		this.cardata = new CarData();
		this.carView = new CarView(this.cardata);
		$('#pushBtn').click(function(){
			self.cardata.setPosX(self.cardata.posX + 20);
		});
	}
}

$(function(){
	var m = new Main();
	m.init();
});

</script>
</head>
<body>

<input id="pushBtn" type="button" value="pushme" />
</body>
</html>

[iOS] EventDispatcher Class in Objective-C

Tuesday, December 28th, 2010

I am a iOS developer, and also a Flash Developer.
I wanted to EventDispatcher class in objective-c.
And I implemented it.

*update Feb.8.2011

IEventDispatcher.h

#import <Foundation/Foundation.h>

@protocol IEventDispatcher
- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener;
- (void)removeEventListener:(NSString *)type target:(id)target;
- (void)dispatchEvent:(NSString *)type;
@end

EventDispatcher.h

#import <Foundation/Foundation.h>
#import "IEventDispatcher.h"

@interface EventDispatcher : NSObject <IEventDispatcher> {
	NSMutableDictionary *targets;
}
@property (nonatomic, retain) NSMutableDictionary *targets;
- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener;
- (void)removeEventListener:(NSString *)type target:(id)target;
- (void)dispatchEvent:(NSString *)type;
@end

EventDispatcher.m


#import "EventDispatcher.h"


@implementation EventDispatcher
@synthesize targets;

- (id)init
{
	if ((self = [super init])) {
		NSMutableDictionary *mytargets = [[NSMutableDictionary alloc] init];
		self.targets = mytargets;
		[mytargets release];
	}
	return self;
}

- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	NSString *identifier = [type stringByAppendingFormat:@"_%d", &(*target)];
	if ([targets valueForKey:identifier] == nil) {
		[center addObserver:target selector:listener name:type object:self];
		[targets setObject:target forKey:identifier];
	}
}

- (void)removeEventListener:(NSString *)type target:(id)target
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	NSString *identifier = [type stringByAppendingFormat:@"_%d", &(*target)];
	if ([targets valueForKey:identifier] != nil) {
		[center removeObserver:target name:type object:self];
		[targets removeObjectForKey:identifier];
	}
}

/**
 * Override this method. if you want to custom userInfo
 */
- (void)dispatchEvent:(NSString *)type
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	[center postNotificationName:type object:self userInfo:nil];
}

- (void)dealloc
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	for(NSString *identifier in targets){
		NSArray *idenntifierArr = [identifier componentsSeparatedByString:@"_"];
		[center removeObserver:[targets objectForKey:identifier] 
						  name:[idenntifierArr objectAtIndex:0] 
						object:self];
	}
	[targets removeAllObjects];
	[targets release];
	[super dealloc];
}
@end

how to use

set handler method

- (void)testHandler:(NSNotification *)aNotification
{
	NSLog(@"test handler");
	
	NSLog(@"name is %@", aNotification.name);
	NSLog(@"object is %@", aNotification.object);
	NSLog(@"info is %@", aNotification.userInfo);
}

and test

    EventDispatcher *myEd = [[[EventDispatcher alloc] init] autorelease];
	[myEd addEventListener:@"EventComplete" target:self listener:@selector(testHandler:)];
	[myEd dispatchEvent:@"EventComplete"];

Sample project file is here.

This article is very useful. Thanks
>> ustom Events in Objective-C | Raphael Wichmann