1+ <!doctype html>
2+ < html >
3+ < head >
4+ < meta charset ="utf-8 " />
5+
6+ < title >
7+ EventEmitter Is An RxJS Observable Stream In Angular 2 Beta 6
8+ </ title >
9+
10+ < link rel ="stylesheet " type ="text/css " href ="./demo.css "> </ link >
11+ </ head >
12+ < body >
13+
14+ < h1 >
15+ EventEmitter Is An RxJS Observable Stream In Angular 2 Beta 6
16+ </ h1 >
17+
18+ < my-app >
19+ Loading...
20+ </ my-app >
21+
22+ <!-- Load demo scripts. -->
23+ < script type ="text/javascript " src ="../../vendor/angularjs-2-beta/6/es6-shim.min.js "> </ script >
24+ < script type ="text/javascript " src ="../../vendor/angularjs-2-beta/6/Rx.umd.min.js "> </ script >
25+ < script type ="text/javascript " src ="../../vendor/angularjs-2-beta/6/angular2-polyfills.min.js "> </ script >
26+ < script type ="text/javascript " src ="../../vendor/angularjs-2-beta/6/angular2-all.umd.js "> </ script >
27+ <!-- AlmondJS - minimal implementation of RequireJS. -->
28+ < script type ="text/javascript " src ="../../vendor/angularjs-2-beta/6/almond.js "> </ script >
29+ < script type ="text/javascript ">
30+
31+ // Defer bootstrapping until all of the components have been declared.
32+ // --
33+ // NOTE: Not all components have to be required here since they will be
34+ // implicitly required by other components.
35+ requirejs (
36+ [ /* Using require() for better readability. */ ] ,
37+ function run ( ) {
38+
39+ var App = require ( "App" ) ;
40+
41+ ng . platform . browser . bootstrap ( App ) ;
42+
43+ }
44+ ) ;
45+
46+
47+ // --------------------------------------------------------------------------- //
48+ // --------------------------------------------------------------------------- //
49+
50+
51+ // I provide the root App component.
52+ define (
53+ "App" ,
54+ function registerApp ( ) {
55+
56+ // Configure the App component definition.
57+ ng . core
58+ . Component ( {
59+ selector : "my-app" ,
60+ // Instead of invoking a callback in our host binding, we're
61+ // actually just piping the local event coordinates directly
62+ // into the mouse stream (which we are subscribing to within
63+ // the component controller).
64+ host : {
65+ "(mousemove)" : "mouseStream.next({ x: $event.pageX, y: $event.pageY });"
66+ } ,
67+ template :
68+ `
69+ <div
70+ class="dot"
71+ [style.left.px]="position.left"
72+ [style.top.px]="position.top">
73+ </div>
74+ `
75+ } )
76+ . Class ( {
77+ constructor : AppController
78+ } )
79+ ;
80+
81+ return ( AppController ) ;
82+
83+
84+ // I control the App component.
85+ function AppController ( ) {
86+
87+ var vm = this ;
88+
89+ // I hold the position of the dot within the bounds of the component.
90+ vm . position = {
91+ left : - 50 ,
92+ top : - 50
93+ } ;
94+
95+ // As the user moves the mouse, we are going to pipe those (x,y)
96+ // coordinates into this EventEmitter instance.
97+ // --
98+ // NOTE: This is populated with .next() values by the host-binding
99+ // on the app component host element.
100+ vm . mouseStream = new ng . core . EventEmitter ( ) ;
101+
102+ // Since EventEmitter inherits from RxJS.Subject, which in turn
103+ // inherits from RxJS.Observable, it means that the EventEmitter, in
104+ // Angular 2, is actually an Observable sequence. Which, of course,
105+ // means that we can operate on it and subscribe to it. In this
106+ // stream, we're going to transform the raw mouse coordinates into
107+ // coordinates that can be used to update the view.
108+ // --
109+ // NOTE: This stream is far more complicated than it needs to be - I
110+ // am simply seizing this as an opportunity to experiment with stream
111+ // mechanics and operators.
112+ vm . mouseStream
113+ // Offset the coordinates away from the mouse.
114+ . map (
115+ function offsetFromCursor ( coordinate ) {
116+
117+ return ( {
118+ x : ( coordinate . x - 25 ) ,
119+ y : ( coordinate . y - 20 )
120+ } ) ;
121+
122+ }
123+ )
124+ // Snap the coordinates to a 25x25 grid system.
125+ . map (
126+ function snapToGrid ( coordinate ) {
127+
128+ var gridSize = 25 ;
129+
130+ return ( {
131+ x : ( coordinate . x - ( coordinate . x % gridSize ) ) ,
132+ y : ( coordinate . y - ( coordinate . y % gridSize ) )
133+ } ) ;
134+
135+ }
136+ )
137+ // Don't pass on the next coordinate value until it has moved
138+ // to another box in the grid system (this one really isn't
139+ // necessary, I'm just experimenting with streams).
140+ . distinctUntilChanged (
141+ function comparator ( a , b ) {
142+
143+ return ( ( a . x === b . x ) && ( a . y === b . y ) ) ;
144+
145+ }
146+ )
147+ // Log out the value that is being passed onto the subscriber.
148+ // This does not affect the outcome of the value chain.
149+ . do (
150+ function asideNext ( value ) {
151+
152+ console . log ( "Passing through (%s,%s)." , value . x , value . y ) ;
153+
154+ }
155+ )
156+
157+ // Here, we are actually subscribing to the stream of
158+ // coordinates which we are using to update the position of the
159+ // Dot in the view.
160+ // --
161+ // CAUTION: If this were a real-world scenario, we'd have to
162+ // capture this subscription and then unsubscribe to it in the
163+ // ngOnDestroy() life-cycle event handler.
164+ . subscribe (
165+ function handleNext ( coordinate ) {
166+
167+ vm . position = {
168+ left : coordinate . x ,
169+ top : coordinate . y
170+ } ;
171+
172+ }
173+ )
174+ ;
175+
176+ }
177+
178+ }
179+ ) ;
180+
181+ </ script >
182+
183+ </ body >
184+ </ html >
0 commit comments