0
# Data Binding and Observables
1
2
Reactive data handling system supporting two-way data binding, change notifications, and observable collections. The data binding system enables automatic UI updates when data changes and supports complex data relationships.
3
4
## Capabilities
5
6
### Observable Class
7
8
Core observable class providing property change notifications and event handling for reactive data management.
9
10
```typescript { .api }
11
/**
12
* Base observable class for reactive data objects
13
*/
14
class Observable {
15
constructor(obj?: any);
16
17
// Property access
18
get(name: string): any;
19
set(name: string, value: any): void;
20
setProperty(name: string, value: any): void;
21
22
// Event handling
23
on(eventName: string, callback: (data: EventData) => void): void;
24
off(eventName: string, callback?: (data: EventData) => void): void;
25
notify(data: EventData): void;
26
notifyPropertyChange(propertyName: string, value: any, oldValue?: any): void;
27
28
// Utility methods
29
hasListeners(eventName: string): boolean;
30
addEventListener(arg: string | EventData, callback?: Function): void;
31
removeEventListener(arg: string | EventData, callback?: Function): void;
32
33
// Static helper
34
static propertyChangeEvent: "propertyChange";
35
}
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { Observable } from "tns-core-modules";
42
43
// Create observable object
44
const user = new Observable({
45
name: "John Doe",
46
age: 30,
47
email: "john@example.com"
48
});
49
50
// Listen for property changes
51
user.on(Observable.propertyChangeEvent, (args) => {
52
console.log(`Property ${args.propertyName} changed from ${args.oldValue} to ${args.value}`);
53
});
54
55
// Update properties (triggers change events)
56
user.set("name", "Jane Doe");
57
user.set("age", 25);
58
59
// Direct property access
60
const currentName = user.get("name");
61
62
// Batch updates
63
user.set("name", "Bob Smith");
64
user.set("email", "bob@example.com");
65
```
66
67
### Observable Array
68
69
Observable array implementation providing standard array functionality with change notifications for reactive collection management.
70
71
```typescript { .api }
72
/**
73
* Observable array with change notifications
74
*/
75
class ObservableArray<T> extends Array<T> {
76
constructor(...items: T[]);
77
78
// Standard array methods (with notifications)
79
push(...items: T[]): number;
80
pop(): T | undefined;
81
shift(): T | undefined;
82
unshift(...items: T[]): number;
83
splice(start: number, deleteCount?: number, ...items: T[]): T[];
84
reverse(): T[];
85
sort(compareFn?: (a: T, b: T) => number): this;
86
87
// Observable functionality
88
on(eventName: string, callback: (data: ChangedData<T>) => void): void;
89
off(eventName: string, callback?: (data: ChangedData<T>) => void): void;
90
notify(data: EventData): void;
91
92
// Collection-specific methods
93
getItem(index: number): T;
94
setItem(index: number, value: T): void;
95
96
// Static event constants
97
static changeEvent: "change";
98
}
99
```
100
101
**Usage Examples:**
102
103
```typescript
104
import { ObservableArray, ChangeType } from "tns-core-modules";
105
106
// Create observable array
107
const items = new ObservableArray<string>("Apple", "Banana", "Orange");
108
109
// Listen for changes
110
items.on(ObservableArray.changeEvent, (args) => {
111
console.log(`Array changed: ${args.action}`);
112
console.log(`Index: ${args.index}, Items: ${args.addedCount}`);
113
});
114
115
// Modify array (triggers change events)
116
items.push("Grape"); // Triggers add event
117
items.splice(1, 1, "Mango"); // Triggers delete + add events
118
const removed = items.pop(); // Triggers delete event
119
120
// Array operations
121
items.sort();
122
items.reverse();
123
124
// Direct access
125
const firstItem = items.getItem(0);
126
items.setItem(1, "Pineapple");
127
```
128
129
### Event Data Interfaces
130
131
Event data structures for observable change notifications and property updates.
132
133
```typescript { .api }
134
/**
135
* Base event data interface
136
*/
137
interface EventData {
138
eventName: string;
139
object: any;
140
}
141
142
/**
143
* Property change event data
144
*/
145
interface PropertyChangeData extends EventData {
146
propertyName: string;
147
value: any;
148
oldValue: any;
149
object: Observable;
150
}
151
152
/**
153
* Array change event data
154
*/
155
interface ChangedData<T> extends EventData {
156
action: ChangeType;
157
index: number;
158
removed: T[];
159
addedCount: number;
160
object: ObservableArray<T>;
161
}
162
163
/**
164
* Change type enumeration for array operations
165
*/
166
enum ChangeType {
167
Add = "add",
168
Delete = "delete",
169
Update = "update",
170
Splice = "splice"
171
}
172
```
173
174
### Virtual Array
175
176
High-performance array implementation for large datasets with virtualization support.
177
178
```typescript { .api }
179
/**
180
* Virtual array for handling large datasets efficiently
181
*/
182
class VirtualArray<T> extends ObservableArray<T> {
183
constructor(length?: number);
184
185
// Virtual array specific properties
186
length: number;
187
188
// Data loading
189
load(index: number, count?: number): T[];
190
loadAsync(index: number, count?: number): Promise<T[]>;
191
192
// Item management
193
getItem(index: number): T;
194
setItem(index: number, item: T): void;
195
requestItemAt(index: number): T;
196
197
// Change detection
198
change(data: ChangedData<T>): void;
199
}
200
```
201
202
### Data Binding Utilities
203
204
Utility functions and classes for advanced data binding scenarios and view model management.
205
206
```typescript { .api }
207
/**
208
* Binding context for data binding operations
209
*/
210
interface BindingContext {
211
$parent?: any;
212
$parents?: any[];
213
$root?: any;
214
$index?: number;
215
$value?: any;
216
}
217
218
/**
219
* Two-way binding helper functions
220
*/
221
namespace Binding {
222
function bind(target: any, targetProperty: string, source: Observable, sourceProperty: string): void;
223
function unbind(target: any, targetProperty: string): void;
224
225
// Binding expressions
226
function getBindingMemberInfo(name: string, source: any): any;
227
function prepareCSS(source: string): string;
228
}
229
230
/**
231
* Property change listener utility
232
*/
233
class WeakRef<T> {
234
constructor(obj: T);
235
get(): T | undefined;
236
clear(): void;
237
}
238
```
239
240
**Advanced Data Binding Examples:**
241
242
```typescript
243
import { Observable, ObservableArray, Page, ListView, Label } from "tns-core-modules";
244
245
// View model with nested observables
246
class UserViewModel extends Observable {
247
private _users: ObservableArray<User>;
248
private _selectedUser: User;
249
250
constructor() {
251
super();
252
this._users = new ObservableArray<User>();
253
this.loadUsers();
254
}
255
256
get users(): ObservableArray<User> {
257
return this._users;
258
}
259
260
get selectedUser(): User {
261
return this._selectedUser;
262
}
263
264
set selectedUser(value: User) {
265
if (this._selectedUser !== value) {
266
this._selectedUser = value;
267
this.notifyPropertyChange("selectedUser", value);
268
}
269
}
270
271
addUser(user: User): void {
272
this._users.push(user);
273
}
274
275
removeUser(index: number): void {
276
this._users.splice(index, 1);
277
}
278
279
private loadUsers(): void {
280
// Simulate loading users
281
this._users.push(
282
new User("John", "john@example.com"),
283
new User("Jane", "jane@example.com")
284
);
285
}
286
}
287
288
class User extends Observable {
289
constructor(public name: string, public email: string) {
290
super();
291
}
292
}
293
294
// Page with data binding
295
export function createPage() {
296
const page = new Page();
297
const viewModel = new UserViewModel();
298
299
// Set binding context
300
page.bindingContext = viewModel;
301
302
// Create UI with data binding
303
const listView = new ListView();
304
listView.bind({
305
sourceProperty: "users",
306
targetProperty: "items"
307
});
308
309
page.content = listView;
310
return page;
311
}
312
```