Views 와 Widgets사이에 커플링을 막고자 사용함.
뷰의 상하의 간에 메시지를 주고 받고 해야 한다.
일반적인 옵저버 패턴.
Broadcasting and Listening
eventHandlerA.on('A', function(data){ alert(data.msg); }); // alerts 'ALERT!'
eventHandlerA.emit('A', message);//trigger
emit나 trigger나 같지만, emit는 밖에서 호출할 때, trigger는 안에서 호출할 때.
Piping
이벤트를 아래로 흐르게 해준다.(like 캡처링)
eventHandlerA.pipe(eventHandlerB).pipe(eventHandlerC); eventHandlerC.on('A', function(data){alert(data.msg)}); // alerts 'ALERT!' eventHandlerA.emit('A', message);
Subscribing
이벤트를 위로 올려준다.(like 버블링)
eventHandlerC.subscribe(eventHandlerB); eventHandlerB.subscribe(eventHandlerA); eventHandlerC.on('A', function(data){alert(data.msg)}); // alerts 'ALERT!' eventHandlerA.emit('A', message);
Filtering
이벤트를 중간에 필터링 해줌.
var myFilter = new EventFilter(function(type, data) { return data && (data.msg === 'ALERT!'); //true or false }); eventHandlerA.pipe(myFilter).pipe(eventHandlerB); eventHandlerB.on('A', function(data){ alert('piped message: ' + data.msg); });
Mapping
라우팅하듯이 특정 eventHandler에 이벤트를 전달한다.(개인적으론 불필요하다고 생각)
var myMapper = new EventMapper(function(type, data) { return (data && (data.direction === 'x')) ? eventHandlerB : eventHandlerC; });
eventHandlerA.pipe(myMapper); eventHandlerB.on('A', function(data){ alert('B direction : ' + data.direction); }); eventHandlerC.on('A', function(data){ alert('C direction : ' + data.direction); }); eventHandlerA.trigger('A', {direction : 'x'}); // pipes to eventHandlerB eventHandlerA.trigger('A', {direction : 'y'}); // pipes to eventHandlerC
pipe만 가능하다.(당연한다 subscribe가 되려면 mapping에서 이벤트를 받아야 함)
Arbitration
Mapping하고 비슷한 느낌인데 mode별로 이벤트를 등록할 수 있다.
한번에 하나의 모드만 가능하고 setMode로 하면 해당 모드만 동작.
이것도 왜 있어야 하는지 모르겠다.
var eventArbiter = new EventArbiter(); eventArbiter.forMode('routeA').on('A', function(data){ alert('subscribed message: ' + data.msg); }); eventArbiter.forMode('routeB').on('B', function(data){ alert('subscribed message: ' + data.msg); }); eventArbiter.setMode('routeA'); eventArbiter.forMode('routeA').emit('A', message); // alerts 'ALERT!' eventArbiter.forMode('routeB').emit('B', message); // does nothing. Mode is not set. eventArbiter.setMode('routeB'); eventArbiter.forMode('routeA').emit('A', message); // does nothing. Mode is not set. eventArbiter.forMode('routeB').emit('B', message); // alerts 'ALERT!'
Event Handling Inside a Widget
자체적으로 몇가지 룰이 있다.
External to a Widget:
widget.trigger : the interface to talk to a widget
widget.on : the interface to listen to a widget
widget.pipe : the interface to pipe from a widget
widget.subscribe : the interface to subscribe from a widget
Internal to a Widget:
receive events via widget.eventInput
broadcast events via widget.eventOutput
widget.emit는 없음.
//아래와 같이 인풋 핸들러를 등록.
EventHandler.setInputHandler(widget, eventHandlerA); eventHandlerA.on('B', function(data){alert(data.msg)}); widget.trigger('B', message);
Listening
setInputHandler으로 등록한 놈이 받음
// Child widget function Child(){ // setup input and output handlers this.eventOutput = new EventHandler(); this.eventInput = new EventHandler(); EventHandler.setInputHandler(this, this.eventInput); EventHandler.setOutputHandler(this, this.eventOutput); this.eventInput.on('hires tutor', function(){ alert('Accepted to Harvard'); }.bind(this)); } // Parent widget function Parent(){ // setup input and output handlers this.eventOutput = new EventHandler(); this.eventInput = new EventHandler(); EventHandler.setInputHandler(this, this.eventInput); EventHandler.setOutputHandler(this, this.eventOutput); this.child = new Child(); this.eventInput.on('bad report card', function(){ this.child.trigger('hires tutor'); }.bind(this)); } var parent = new Parent(); parent.trigger('bad report card');
Broadcasting
setOutputHandler으로 등록한 얘가 전달.
EventHandler.setInputHandler(widget, eventHandlerA); eventHandlerA.on('B', function(data){alert(data.msg)}); widget.trigger('B', message);
보면서 느낀건 전체적으로 과한 느낌이 있다.
너무 많다. 이런 경우 나중에 이벤트로만 넣으면 데이터가 흘러갈 때 문제가 있을 것 같다.
특히 mapping은 불필요. 데이터가 deep copy되지 않기 때문에 중간에 값을 바꾸면 디버깅의 거의 불가능하고 경험상 이벤트 종류는 너무 할 정도로 간단하게 가야 한다. 복잡하게 되면 나중에 엄청 고생함.