|  | 
|  | 1 | +--- | 
|  | 2 | +nav-title: "NativeScript Events" | 
|  | 3 | +title: "Events" | 
|  | 4 | +description: "NativeScript Documentation: Events" | 
|  | 5 | +position: 66 | 
|  | 6 | +--- | 
|  | 7 | + | 
|  | 8 | +#Events | 
|  | 9 | + | 
|  | 10 | +##Overview | 
|  | 11 | + | 
|  | 12 | +Event is a message sent from the event emitter for the occurrence of a specific action. This action could be generated by user action (such as finger tap), or by some program logic (indicates that downloading an image from a server is completed). The object that raises event is called **event sender** or just **sender**. The object that consumes the event is called **event listener** or just **listener**. Being a TypeScript (JavaScript) framework NativeScript cannot benefit from any language built-in event handling mechanism. Since events are very critical for any modern mobile application development NativeScript provides a class that powers the process of working with events. This class is called Observable ([API-Ref](./ApiReference/data/observable/observable.md)). | 
|  | 13 | + | 
|  | 14 | +##How events work | 
|  | 15 | + | 
|  | 16 | +Generally events are very similar to a radio station: **sender** plays music (fires an event) and **listener** dances (executes an action). As mentioned, NativeScript streamlines the events task with a class called Observable. It is one of the very basic classes within NativeScript framework so almost every NativeScript object (component) has an option for dealing with events. | 
|  | 17 | + | 
|  | 18 | +##Adding an event listener | 
|  | 19 | + | 
|  | 20 | +Adding an **event listener** means setting a function (method) which should be executed when event is raised. The example below shows how a function that prints a "Hello World!" message on the console is set to be executed when **button** is tapped. | 
|  | 21 | + | 
|  | 22 | +* Adding an event handler with a short-hand syntax | 
|  | 23 | + | 
|  | 24 | +This syntax is used to write an in-line function which should be executed when the **testButton** is tapped. | 
|  | 25 | + | 
|  | 26 | +``` JavaScript | 
|  | 27 | +var buttonModule = require("ui/button"); | 
|  | 28 | +var testButton = new buttonModule.Button(); | 
|  | 29 | +testButton.text = "Test"; | 
|  | 30 | + | 
|  | 31 | +testButton.on(buttonModule.knownEvents.tap, function (eventData) { | 
|  | 32 | + console.log("Hello World!"); | 
|  | 33 | +}); | 
|  | 34 | +``` | 
|  | 35 | +``` TypeScript | 
|  | 36 | +import buttonModule = require("ui/button"); | 
|  | 37 | +var testButton = new buttonModule.Button(); | 
|  | 38 | +testButton.text = "Test"; | 
|  | 39 | + | 
|  | 40 | +testButton.on(buttonModule.knownEvents.tap, function (eventData) { | 
|  | 41 | + console.log("Hello World!"); | 
|  | 42 | + }); | 
|  | 43 | +``` | 
|  | 44 | + | 
|  | 45 | +Even though this short-hand syntax is very handy to assign some very simple functions it is missing some important features available in the original syntax: | 
|  | 46 | + | 
|  | 47 | +* Adding an event handler | 
|  | 48 | + | 
|  | 49 | +``` JavaScript | 
|  | 50 | +var buttonModule = require("ui/button"); | 
|  | 51 | +var testButton = new buttonModule.Button(); | 
|  | 52 | +testButton.text = "Test"; | 
|  | 53 | + | 
|  | 54 | +var onTap = function (eventData) { | 
|  | 55 | + console.log("Hello World!"); | 
|  | 56 | +}; | 
|  | 57 | + | 
|  | 58 | +testButton.addEventListener(buttonModule.knownEvents.tap, onTap, this); | 
|  | 59 | +``` | 
|  | 60 | +``` TypeScript | 
|  | 61 | +import buttonModule = require("ui/button"); | 
|  | 62 | +var testButton = new buttonModule.Button(); | 
|  | 63 | +testButton.text = "Test"; | 
|  | 64 | + | 
|  | 65 | +var onTap = function (eventData) { | 
|  | 66 | + console.log("Hello World!"); | 
|  | 67 | +}; | 
|  | 68 | + | 
|  | 69 | +testButton.addEventListener(buttonModule.knownEvents.tap, onTap, this); | 
|  | 70 | +``` | 
|  | 71 | +The only difference here is the third optional parameter which represents the **this** argument which will be used as **event handler** context (closure). In other words, if you need a **this** argument in your event handler function you have to use the long syntax, otherwise the **sender** object is used as the **this**. | 
|  | 72 | + | 
|  | 73 | +* Adding an event handler with an xml declaration | 
|  | 74 | + | 
|  | 75 | +Another option to set an event handler is via an xml declaration. | 
|  | 76 | + | 
|  | 77 | +``` XML | 
|  | 78 | +<Page> | 
|  | 79 | + <StackPanel> | 
|  | 80 | + <Button tap="onTap" /> | 
|  | 81 | + </StackPanel> | 
|  | 82 | +</Page> | 
|  | 83 | +``` | 
|  | 84 | +Of course we need a code behind file in order to write the body of the function. (Code behind file has same name as **xml** with **js** or **ts** extension). | 
|  | 85 | + | 
|  | 86 | +``` JavaScript | 
|  | 87 | +function onTap(eventData) { | 
|  | 88 | + console.log("Hello World!"); | 
|  | 89 | +} | 
|  | 90 | +exports.listViewItemTap = listViewItemTap; | 
|  | 91 | +``` | 
|  | 92 | +``` TypeScript | 
|  | 93 | +export function onTap(eventData) { | 
|  | 94 | + console.log("Hello World!"); | 
|  | 95 | +} | 
|  | 96 | +``` | 
|  | 97 | + | 
|  | 98 | +##Removing an event listener | 
|  | 99 | + | 
|  | 100 | +Usually there is no need to remove the **event listener**. However there are some scenarios where we need to receive the event just once, or just remove the event listener in order to free resources. | 
|  | 101 | + | 
|  | 102 | +* Remove an event listener with a short-hand syntax | 
|  | 103 | + | 
|  | 104 | +``` JavaScript | 
|  | 105 | +testButton.off(buttonModule.knownEvents.tap); | 
|  | 106 | +``` | 
|  | 107 | +``` TypeScript | 
|  | 108 | +testButton.off(buttonModule.knownEvents.tap); | 
|  | 109 | +``` | 
|  | 110 | +This will remove all listeners for the tap event of the testButton instance. If there are more than one **event listener** objects, a second parameter with the name of the callback function could be set so that only the referenced event listener will be removed. | 
|  | 111 | + | 
|  | 112 | +* Remove an event listener, long syntax | 
|  | 113 | + | 
|  | 114 | +``` JavaScript | 
|  | 115 | +testButton.removeEventListener(buttonModule.knownEvents.tap, onTap); | 
|  | 116 | +``` | 
|  | 117 | +``` TypeScript | 
|  | 118 | +testButton.removeEventListener(buttonModule.knownEvents.tap, onTap); | 
|  | 119 | +``` | 
|  | 120 | +The difference between short and long syntax is the option of the long syntax to specify the **this** argument (which was used to add the event listener) if there are many event listeners with different **this** arguments. | 
|  | 121 | + | 
|  | 122 | +> There is no syntax to remove an event listener via an xml declaration. | 
|  | 123 | +
 | 
|  | 124 | +##PropertyChange event | 
|  | 125 | + | 
|  | 126 | +Observable class has a built-in event called **propertyChange** which is called when any property has been changed. Subscribing to this event is very similar to previous examples. | 
|  | 127 | + | 
|  | 128 | +``` JavaScript | 
|  | 129 | +var observableModule = require("data/observable"); | 
|  | 130 | +var observableObject = new observableModule.Observable(); | 
|  | 131 | + | 
|  | 132 | +observableObject.on(observableModule.knownEvents.propertyChange, function(propertyChangeData){ | 
|  | 133 | + console.log(propertyChangeData.propertyName + " has been changed and new value is: " + propertyChangeData.value); | 
|  | 134 | +}); | 
|  | 135 | +``` | 
|  | 136 | +``` TypeScript | 
|  | 137 | +import observableModule = require("data/observable"); | 
|  | 138 | +var observableObject = new observableModule.Observable(); | 
|  | 139 | + | 
|  | 140 | +observableObject.on(observableModule.knownEvents.propertyChange, function(propertyChangeData){ | 
|  | 141 | + console.log(propertyChangeData.propertyName + " has been changed and new value is: " + propertyChangeData.value); | 
|  | 142 | +}); | 
|  | 143 | +``` | 
|  | 144 | +What is important about this event is that it is very critical for the entire [data binding](./bindings.md) system to work. In order to take advantage of the data binding mechanism it is enough to simply make your business object **inherit** of the Observable class. The following example demonstrates how to do that: | 
|  | 145 | + | 
|  | 146 | +``` JavaScript | 
|  | 147 | +var observableModule = require("data/observable"); | 
|  | 148 | +var MyClass = (function (_super) { | 
|  | 149 | + __extends(MyClass, _super); | 
|  | 150 | + function MyClass() { | 
|  | 151 | + _super.apply(this, arguments); | 
|  | 152 | + } | 
|  | 153 | + Object.defineProperty(MyClass.prototype, "myProperty", { | 
|  | 154 | + get: function () { | 
|  | 155 | + return this.get("myProperty"); | 
|  | 156 | + }, | 
|  | 157 | + set: function (value) { | 
|  | 158 | + this.set("myProperty", value); | 
|  | 159 | + }, | 
|  | 160 | + enumerable: true, | 
|  | 161 | + configurable: true | 
|  | 162 | + }); | 
|  | 163 | + return MyClass; | 
|  | 164 | + })(observableModule.Observable); | 
|  | 165 | +exports.MyClass = MyClass; | 
|  | 166 | +``` | 
|  | 167 | +``` TypeScript | 
|  | 168 | +import observableModule = require("data/observable"); | 
|  | 169 | + | 
|  | 170 | +export class MyClass extends observableModule.Observable { | 
|  | 171 | + public get myProperty(): number { | 
|  | 172 | + return this.get("myProperty"); | 
|  | 173 | + } | 
|  | 174 | + | 
|  | 175 | + public set myProperty(value: number) { | 
|  | 176 | + this.set("myProperty", value); | 
|  | 177 | + } | 
|  | 178 | +} | 
|  | 179 | +``` | 
|  | 180 | +This code snippet will fire the **propertyChange** event when the value of the property is changed out-of-the-box. | 
|  | 181 | + | 
|  | 182 | +##Creating a custom event | 
|  | 183 | + | 
|  | 184 | +Using Observable, methods **get** and **set** works just great for the **propertyChange** event. In many cases, according to some business logic, there is a need to create a custom event. To fire (raise or emit) an event all we have to do is to Observable.notify() method with proper event data when the action is completed. By proper event data we refer to any **implementer** of the [EventData interface](./ApiReference/data/observable/EventData.md). This is the very basic information about an event (its name as **eventName** and instance of the **event sender** as **object**). | 
|  | 185 | + | 
|  | 186 | +``` JavaScript | 
|  | 187 | +var eventData = { | 
|  | 188 | + eventName: "myCustomEventName", | 
|  | 189 | + object: this | 
|  | 190 | +}; | 
|  | 191 | +this.notify(eventData); | 
|  | 192 | +``` | 
|  | 193 | +``` TypeScript | 
|  | 194 | +var eventData: observableModule.EventData = { | 
|  | 195 | + eventName: "myCustomEventName", | 
|  | 196 | + object: this | 
|  | 197 | +} | 
|  | 198 | +this.notify(eventData); | 
|  | 199 | +``` | 
|  | 200 | +The bare minimum needed to raise an event is the eventName - it will be used to execute all **event handlers** associated with this event. | 
|  | 201 | + | 
|  | 202 | +Next step is to hook for this event. | 
|  | 203 | + | 
|  | 204 | +``` JavaScript | 
|  | 205 | +var myCustomObject = new MyClass(); | 
|  | 206 | +myCustomObject.on("myCustomEventName", function(eventData){ | 
|  | 207 | + console.log(eventData.eventName + " has been raised! by: " + eventData.object); | 
|  | 208 | +}) | 
|  | 209 | +``` | 
|  | 210 | +Almost the same logic is implemented for the **propertyChange** event, so if your business logic has some special requirements **propertyChange** could be emitted manually via **notify()** method (without using Observable.set() method which also fires the **propertyChange** event). | 
|  | 211 | + | 
|  | 212 | +##Avoiding memory leaks | 
|  | 213 | + | 
|  | 214 | +Though the radio station comparison is convenient for understanding the concept, the situation is a bit more complicated in the inside. In order to be able to notify the listener, the sender has a pointer to the listener. This means that even if that listener object gets set to `null` or `undefined`, it is not eligible for garbage collection, since the sender is alive and has a live reference to the listener object. This could result in a memory leak in some scenarios when object lifetimes of the sender and the listener are quite different. Here's an example scenario: a UI element creates a lot of child controls, where every control hooks for an event of the parent and then a child control gets released (very similar to list view scrolling). In order to prevent such memory leaks it is a good practice to remove your event listener handler before releasing the listener object. Unfortunately in some cases we could define the exact time when we should call (off or removeEventListener) functions. Here comes another option in NativeScript framework **weakEvents**. | 
|  | 215 | + | 
|  | 216 | +##Working with weak events | 
|  | 217 | + | 
|  | 218 | +* Adding a weak event listener | 
|  | 219 | + | 
|  | 220 | +Weak events as its name suggests creates an weak reference to the **listener** object, which allows this listener object to be released without removing the **event listener** pointer. Using weak event listeners is very similar to *normal* events. Here is the example with comments for each line. | 
|  | 221 | + | 
|  | 222 | +``` JavaScript | 
|  | 223 | +var weakEventListenerModule = require("ui/core/weakEventListener"); | 
|  | 224 | +var buttonModule = require("ui/button"); | 
|  | 225 | +var observableModule = require("data/observable"); | 
|  | 226 | + | 
|  | 227 | +var testButton = new buttonModule.Button(); | 
|  | 228 | +testButton.text = "Test"; | 
|  | 229 | +testButton.on(buttonModule.knownEvents.tap, function () { | 
|  | 230 | + source.set("testProperty", "change" + counter); | 
|  | 231 | + }); | 
|  | 232 | + | 
|  | 233 | + var source = new observableModule.Observable(); | 
|  | 234 | + | 
|  | 235 | + var counter = 0; | 
|  | 236 | + var handlePropertyChange = function () { | 
|  | 237 | + counter++; | 
|  | 238 | + this.text = counter + ""; | 
|  | 239 | + }; | 
|  | 240 | + | 
|  | 241 | + var weakEL = weakEventListenerModule.WeakEventListener; | 
|  | 242 | + var weakEventListenerOptions: weakEventListenerModule.WeakEventListenerOptions = { | 
|  | 243 | + // a weak reference of the event listener object | 
|  | 244 | + targetWeakRef: new WeakRef(this), | 
|  | 245 | + // a weak reference if the event sender object | 
|  | 246 | + sourceWeakRef: new WeakRef(this.source), | 
|  | 247 | + // the name of the event | 
|  | 248 | + eventName: observable.knownEvents.propertyChange, | 
|  | 249 | + // the handler of the event | 
|  | 250 | + handler: handlePropertyChange, | 
|  | 251 | + // the context which will be used to execute the handler (optional) | 
|  | 252 | + handlerContext: testButton, | 
|  | 253 | + // a special property which is used for a extra event recognition (optional) | 
|  | 254 | + key: this.options.targetProperty | 
|  | 255 | + } | 
|  | 256 | + weakEL.addWeakEventListener(this.weakEventListenerOptions); | 
|  | 257 | +``` | 
|  | 258 | +``` TypeScript | 
|  | 259 | +import weakEventListenerModule = require("ui/core/weakEventListener"); | 
|  | 260 | +import buttonModule = require("ui/button"); | 
|  | 261 | +import observableModule = require("data/observable"); | 
|  | 262 | + | 
|  | 263 | +var testButton = new buttonModule.Button(); | 
|  | 264 | +testButton.text = "Test"; | 
|  | 265 | +testButton.on(buttonModule.knownEvents.tap, function () { | 
|  | 266 | + source.set("testProperty", "change" + counter); | 
|  | 267 | +}); | 
|  | 268 | + | 
|  | 269 | +var source = new observableModule.Observable(); | 
|  | 270 | + | 
|  | 271 | +var counter = 0; | 
|  | 272 | +var handlePropertyChange = function () { | 
|  | 273 | + counter++; | 
|  | 274 | + this.text = counter + ""; | 
|  | 275 | +}; | 
|  | 276 | + | 
|  | 277 | +var weakEL = weakEventListenerModule.WeakEventListener; | 
|  | 278 | +var weakEventListenerOptions: weakEventListenerModule.WeakEventListenerOptions = { | 
|  | 279 | + // a weak reference of the event listener object | 
|  | 280 | + targetWeakRef: new WeakRef(this), | 
|  | 281 | + // a weak reference if the event sender object | 
|  | 282 | + sourceWeakRef: new WeakRef(this.source), | 
|  | 283 | + // the name of the event | 
|  | 284 | + eventName: observable.knownEvents.propertyChange, | 
|  | 285 | + // the handler of the event | 
|  | 286 | + handler: handlePropertyChange, | 
|  | 287 | + // the context which will be used to execute the handler (optional) | 
|  | 288 | + handlerContext: testButton, | 
|  | 289 | + // a special property which is used for a extra event recognition (optional) | 
|  | 290 | + key: this.options.targetProperty | 
|  | 291 | +} | 
|  | 292 | +weakEL.addWeakEventListener(this.weakEventListenerOptions); | 
|  | 293 | +``` | 
|  | 294 | + | 
|  | 295 | +Previous example shows how to attach a **weak event listener** to an observable object instance. A closer look to the **handlePropertyChange** function shows that **text** property of the **this** object is changed when the **propertyChange** event is raised (via the button tap event). It demonstrates how to use the **handlerContext** property - the value of this property is taken as a **this** argument inside the **event handler** function. | 
|  | 296 | +Generally **targetWeakRef** and **key** properties are not needed to invoke a function when an event is raised. However these properties support another useful option of the weak event listener (a possibility to remove an event listener) both properties are used as keys for a key-value pair that stores weak event listeners. | 
|  | 297 | + | 
|  | 298 | +* Removing weak event listener | 
|  | 299 | + | 
|  | 300 | +``` JavaScript | 
|  | 301 | +weakEL.removeWeakEventListener(this.weakEventListenerOptions); | 
|  | 302 | +``` | 
|  | 303 | +``` TypeScript | 
|  | 304 | +weakEL.removeWeakEventListener(this.weakEventListenerOptions); | 
|  | 305 | +``` | 
0 commit comments