@maccesar/titools 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +31 -60
  3. package/agents/ti-pro.md +3 -1
  4. package/commands/ti-audit.md +6 -4
  5. package/docs/examples.md +9 -0
  6. package/docs/knowledge-index.md +2 -1
  7. package/lib/config.js +1 -0
  8. package/package.json +1 -1
  9. package/skills/alloy-guides/SKILL.md +18 -179
  10. package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
  11. package/skills/alloy-guides/references/CONCEPTS.md +27 -162
  12. package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
  13. package/skills/alloy-guides/references/MODELS.md +47 -723
  14. package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
  15. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
  16. package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
  17. package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
  18. package/skills/alloy-guides/references/WIDGETS.md +49 -127
  19. package/skills/alloy-howtos/SKILL.md +14 -169
  20. package/skills/alloy-howtos/references/best_practices.md +9 -113
  21. package/skills/alloy-howtos/references/cli_reference.md +18 -223
  22. package/skills/alloy-howtos/references/config_files.md +50 -133
  23. package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
  24. package/skills/alloy-howtos/references/samples.md +21 -138
  25. package/skills/ti-api/SKILL.md +10 -2
  26. package/skills/ti-api/references/api-android.md +36 -2
  27. package/skills/ti-api/references/api-app-platform.md +39 -3
  28. package/skills/ti-api/references/api-core.md +50 -18
  29. package/skills/ti-api/references/api-data-network.md +49 -35
  30. package/skills/ti-api/references/api-media.md +45 -27
  31. package/skills/ti-api/references/api-services.md +39 -9
  32. package/skills/ti-api/references/api-ui-android.md +33 -13
  33. package/skills/ti-api/references/api-ui-extras.md +41 -15
  34. package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
  35. package/skills/ti-api/references/api-ui-ios.md +74 -2
  36. package/skills/ti-api/references/api-ui-lists.md +32 -16
  37. package/skills/ti-api/references/api-ui-text-input.md +34 -17
  38. package/skills/ti-api/references/api-ui-views.md +27 -1
  39. package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
  40. package/skills/ti-api/references/api-xml-global.md +66 -16
  41. package/skills/ti-create-release/SKILL.md +98 -0
  42. package/skills/ti-create-release/references/module-discovery.md +69 -0
  43. package/skills/ti-expert/references/adaptive-layouts.md +1 -1
  44. package/skills/ti-guides/SKILL.md +37 -76
  45. package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
  46. package/skills/ti-guides/references/android-manifest.md +24 -83
  47. package/skills/ti-guides/references/app-distribution.md +31 -377
  48. package/skills/ti-guides/references/application-frameworks.md +127 -335
  49. package/skills/ti-guides/references/cli-reference.md +184 -633
  50. package/skills/ti-guides/references/commonjs-advanced.md +81 -231
  51. package/skills/ti-guides/references/compatibility-matrix.md +36 -75
  52. package/skills/ti-guides/references/hello-world.md +95 -70
  53. package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
  54. package/skills/ti-guides/references/resources.md +174 -142
  55. package/skills/ti-guides/references/sdk-release-notes.md +28 -71
  56. package/skills/ti-guides/references/tiapp-config.md +222 -598
  57. package/skills/ti-howtos/SKILL.md +23 -123
  58. package/skills/ti-howtos/references/cross-platform-development.md +119 -324
  59. package/skills/ti-howtos/references/debugging-profiling.md +77 -445
  60. package/skills/ti-howtos/references/extending-titanium.md +199 -673
  61. package/skills/ti-howtos/references/local-data-sources.md +87 -300
  62. package/skills/ti-howtos/references/location-and-maps.md +86 -213
  63. package/skills/ti-howtos/references/media-apis.md +103 -223
  64. package/skills/ti-howtos/references/notification-services.md +86 -506
  65. package/skills/ti-howtos/references/remote-data-sources.md +97 -316
  66. package/skills/ti-howtos/references/using-modules.md +77 -133
  67. package/skills/ti-ui/SKILL.md +28 -143
  68. package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
  69. package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
  70. package/skills/ti-ui/references/listviews-and-performance.md +100 -703
  71. package/skills/ti-ui/references/platform-conventions.md +180 -0
  72. package/skills/ti-ui/references/user-interface.md +43 -0
  73. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  74. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  75. package/skills/ti-guides/references/coding-best-practices.md +0 -149
  76. package/skills/ti-guides/references/javascript-primer.md +0 -414
  77. package/skills/ti-guides/references/reserved-words.md +0 -36
  78. package/skills/ti-guides/references/style-and-conventions.md +0 -103
  79. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
  80. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  81. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  82. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  83. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  84. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
  85. package/skills/ti-howtos/references/tutorials.md +0 -565
  86. package/skills/ti-howtos/references/web-content-integration.md +0 -287
  87. package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
  88. package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
  89. package/skills/ti-ui/references/animation-and-matrices.md +0 -569
  90. package/skills/ti-ui/references/application-structures.md +0 -626
  91. package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
  92. package/skills/ti-ui/references/event-handling.md +0 -401
  93. package/skills/ti-ui/references/gestures.md +0 -448
  94. package/skills/ti-ui/references/orientation.md +0 -374
  95. package/skills/ti-ui/references/platform-ui-android.md +0 -727
  96. package/skills/ti-ui/references/platform-ui-ios.md +0 -576
  97. package/skills/ti-ui/references/scrolling-views.md +0 -288
  98. package/skills/ti-ui/references/tableviews.md +0 -542
@@ -1,765 +1,89 @@
1
- # Alloy Models
1
+ # Alloy models, collections and binding
2
2
 
3
- Models, collections, and how to bind them to views in Alloy. For sync adapters, migrations, plain Backbone usage, and the Backbone 0.9.2 → 1.1.2 / 1.3.3 migration, see [MODELS_ADVANCED.md](MODELS_ADVANCED.md).
3
+ A Backbone model is a record with attributes and events; a collection holds models. Alloy adds persistence through a sync adapter selected per model. Use this layer for data shared across screens, persistent data or state that outlives a screen. A one-shot response can use `Ti.Network` and a plain array instead.
4
4
 
5
- 1. [Overview](#overview)
6
- 2. [Alloy Collection and Model Objects](#alloy-collection-and-model-objects)
7
- 3. [Alloy Data Binding](#alloy-data-binding)
8
-
9
- <!-- TOC-START -->
10
- ## Contents
11
-
12
- - [Overview](#overview)
13
- - [Alloy Collection and Model Objects](#alloy-collection-and-model-objects)
14
- - [Models](#models)
15
- - [Collections](#collections)
16
- - [Event Handling](#event-handling)
17
- - [Alloy Data Binding](#alloy-data-binding)
18
- - [Introduction](#introduction)
19
- - [Alloy Binding](#alloy-binding)
20
- - [Collection vs Model Data Binding](#collection-vs-model-data-binding)
21
- - [Global Singleton vs Local Instance](#global-singleton-vs-local-instance)
22
- - [Simple vs Complex Data Binding](#simple-vs-complex-data-binding)
23
- - [Backbone Binding](#backbone-binding)
24
- - [Bind Deep Object Properties](#bind-deep-object-properties)
25
- - [Use Models and Properties with Special Characters](#use-models-and-properties-with-special-characters)
26
- - [Bind Multiple Models to the Same View](#bind-multiple-models-to-the-same-view)
27
- - [Define Transformations in the Model](#define-transformations-in-the-model)
28
- - [Tips and Tricks](#tips-and-tricks)
29
-
30
- <!-- TOC-END -->
31
-
32
- ## Overview
33
-
34
- Alloy uses Backbone.js to provide support for its models and collections. Alloy also borrows the concepts of migrations and adapters from Rails for storage integration.
35
-
36
- For models, collections and sync adapters, these guides only provides information on how Alloy uses the Backbone.js functionality and some simple examples of using it.
37
-
38
- ## Alloy Collection and Model Objects
39
-
40
- ### Models
41
-
42
- In Alloy, models inherit from the [Backbone.Model](https://backbonejs.org/#Model-View-separation) class. They contain the interactive data and logic used to control and access it. Models are specified with JavaScript files, which provide a table schema, adapter configuration and logic to extend the Backbone.Model class. Models are automatically defined and available in the controller scope as the name of the JavaScript file.
43
-
44
- The JavaScript file exports a definition object comprised of three different objects. The first object, called `config`, defines the table schema and adapter information. The next two objects `extendModel` and `extendCollection` define functions to extend, override or implement the Backbone.Model and Backbone.Collection classes, respectively.
45
-
46
- **Example of the anatomy of a model file**
47
-
48
- ```
49
- exports.definition = {
50
- config : { // table schema and adapter information
51
- },
52
- extendModel(Model) {
53
- _.extend(Model.prototype, { // Extend, override or implement Backbone.Model
54
- });
55
-
56
- return Model;
57
- },
58
- extendCollection(Collection) {
59
- _.extend(Collection.prototype, { // Extend, override or implement Backbone.Collection
60
- });
61
-
62
- return Collection;
63
- }
64
- }
65
- ```
66
-
67
- To access a model locally in a controller, use the `Alloy.createModel` method. The first required parameter is the name of the JavaScript file minus the '.js' extension. The second optional parameter is the attributes for initializing the model object. For example:
68
-
69
- **Basic model usage**
70
-
71
- ```javascript
72
- const book = Alloy.createModel('book', {title:'Green Eggs and Ham', author:'Dr. Seuss'});
73
- const title = book.get('title');
74
- const author = book.get('author');
75
-
76
- // Label object in the view with id = 'label'
77
- $.label.text = title + ' by ' + author;
78
- ```
79
-
80
- The `book` model object is a Backbone object wrapped by Alloy, so it can be treated as a Backbone.Model object. You can use any Backbone Model or Events APIs with this object.
81
-
82
- You can also create a global singleton instance of a model, either in markup or in the controller, which may be accessed in all controllers. Use the `Alloy.Models.instance` method with the name of the model file minus the extension as the only parameter to create or access the singleton. For example:
83
-
84
- **Working with globally registered models**
85
-
86
- ```javascript
87
- // This will create a singleton if it has not been previously created,
88
- // or retrieves the singleton if it already exists.
89
- const book = Alloy.Models.instance('book');
90
- ```
91
-
92
- #### Configuration Object
93
-
94
- The `config` object is comprised of three different objects: `columns`, `defaults` and `adapter`.
95
-
96
- The `columns` object defines the table schema information. The key is the record name and the value is the data type. The following data types are accepted and mapped to the appropriate SQLite type: `string`, `varchar`, `int`, `tinyint`, `smallint`, `bigint`, `double`, `float`, `decimal`, `number`, `date`, `datetime` and `boolean`. By default, any unknown data type maps to the SQLite type `TEXT`. Alternatively, the SQLite sync adapter accepts the SQLite keywords.
97
-
98
- The optional `defaults` object defines the default values for a record if one or more record fields are left undefined upon creation. The key is the record name and the value is the default value.
99
-
100
- The adapter object defines how to access persistent storage. It contains two key-value pairs: `type` and `collection_name`. The `type` key identifies the sync adapter and the `collection_name` key identifies the name of the table in the database or a namespace.
101
-
102
- For example, suppose there is a model object called book (`book.js`) defined as:
103
-
104
- **book.js**
5
+ ## Define and use a model
105
6
 
106
7
  ```javascript
8
+ // app/models/note.js
107
9
  exports.definition = {
108
10
  config: {
109
- "columns": {
110
- "title": "String",
111
- "author": "String"
112
- },
113
- "defaults": {
114
- "title": "-",
115
- "author": "-"
11
+ columns: {
12
+ id: 'INTEGER PRIMARY KEY AUTOINCREMENT',
13
+ body: 'TEXT',
14
+ done: 'INTEGER'
116
15
  },
117
- "adapter": {
118
- "type": "sql",
119
- "collection_name": "books"
16
+ adapter: {
17
+ type: 'sql',
18
+ collection_name: 'notes',
19
+ idAttribute: 'id'
120
20
  }
121
- }
122
- }
123
- ```
124
-
125
- The code above describes a book object, which has two `string` (or `TEXT`) fields: `title` and `author`. If either field is left undefined, it will be assigned with the default value, a dash ("-"). The `sql` type configures Backbone to use the SQL adapter to sync with the SQLite engine on Android and iOS devices to access a table in the database called "books".
126
-
127
- You may add custom properties to the `config` object, which are available to the application as the model or collection's `config` property or can be processed by a custom sync adapter during application initialization.
128
-
129
- #### Extending the Backbone.Model Class
130
-
131
- The Backbone.Model class can be extended using the `extendModel` object, which implements the Backbone.Model `extend` method. This allows the Backbone.js code to be extended, overridden or implemented.
132
-
133
- For example, the `validate` method is left unimplemented by Backbone.js. The model JS file can implement `validate(attrs)`, where the parameter `attrs` are changed attributes in the model. In Backbone.js, if `validate` is implemented, it is called by the `set` and `save(attributes)` methods before changing the attributes and is also called by the `isValid` method. For the `save` method, validate is called if the `attributes` parameter is defined.
134
-
135
- In the example code `book.js` below, the JavaScript file implements the validate method, and adds a custom property and function.
136
-
137
- **Extending a model**
138
-
139
- ```javascript
140
- exports.definition = {
141
- config : { // table schema and adapter information
142
21
  },
143
-
144
22
  extendModel(Model) {
145
23
  _.extend(Model.prototype, {
146
- // Implement the validate method
147
- validate(attrs) {
148
- for (const key in attrs) {
149
- const value = attrs[key];
150
- if (key === "title") {
151
- if (value.length <= 0) {
152
- return "Error: No title!";
153
- }
154
- }
155
- if (key === "author") {
156
- if (value.length <= 0) {
157
- return "Error: No author!";
158
- }
159
- }
160
- }
161
- },
162
- // Extend Backbone.Model
163
- customProperty: 'book',
164
- customFunction() {
165
- Ti.API.info('I am a book model.');
166
- },
167
- });
168
-
169
- return Model;
170
- }
171
- }
172
- ```
173
-
174
- In the controller, to access the model, do:
175
-
176
- ```javascript
177
- const book = Alloy.createModel('book', {title:'Green Eggs and Ham', author:'Dr. Seuss'});
178
- // Since set or save(attribute) is not being called, we can call isValid to validate the model object
179
- if (book.isValid() && book.customProperty == "book") { // Save data to persistent storage
180
- book.save();
181
- }
182
- else {
183
- book.destroy();
184
- }
185
- ```
186
-
187
- ### Collections
188
-
189
- Collections are ordered sets of models and inherit from the Backbone.Collection class. Alloy Collections are automatically defined and available in the controller scope as the name of the model. To access a collection in the controller locally, use the `Alloy.createCollection` method with the name of the JavaScript file minus the '.js' extension as the required parameter. The second optional parameter can be an array of model objects for initialization. For example, the code below creates a collection using the previously defined model and reads data from persistent storage:
190
-
191
- **Creating collections**
192
-
193
- ```javascript
194
- const library = Alloy.createCollection('book');
195
- library.fetch(); // Grab data from persistent storage
196
- ```
197
-
198
- The `library` collection object is a Backbone object wrapped by Alloy, so it can be treated as a Backbone.Collection object. You can use any Backbone Collection or Events APIs with this object.
199
-
200
- You can also create a global singleton instance, either in markup or in the controller, which may be accessed in all controllers. Use the `Alloy.Collections.instance` method with the name of the model file minus the extension as the only parameter to create or access the singleton. For example:
201
-
202
- **Working with globally registered collections**
203
-
204
- ```javascript
205
- // This will create a singleton if it has not been previously created,
206
- // or retrieves the singleton if it already exists.
207
- const library = Alloy.Collections.instance('book');
208
- ```
209
-
210
- #### Extending the Backbone.Collection Class
211
-
212
- Like the Backbone.Model class, the Backbone.Collection class can be similarly extended in the model JavaScript file. For example, the `comparator` method is left unimplemented in Backbone.js. The code below sorts the library by book title:
213
-
214
- **Extending a collection**
215
-
216
- ```
217
- exports.definition = {
218
- config : { // table schema and adapter information
219
- },
220
- extendModel(Model) {
221
- _.extend(Model.prototype, { // Extend, override or implement Backbone.Model methods
24
+ toggle() {
25
+ this.save({ done: this.get('done') ? 0 : 1 });
26
+ }
222
27
  });
223
28
  return Model;
224
- },
225
- extendCollection(Collection) {
226
- _.extend(Collection.prototype, { // Implement the comparator method.
227
- comparator(book) {
228
- return book.get('title');
229
- }
230
- }); // end extend
231
-
232
- return Collection;
233
29
  }
234
- }
235
- ```
236
-
237
- #### Underscore.js Functionality
238
-
239
- Also, the Backbone.Collection class inherits some functionality from [Underscore.js](https://underscorejs.org/), which can help simplify iterative functions. For example, to add the title of each book object in the library collection to a table, you could use the `map` function to set the table:
240
-
241
- **Iterating over a collection with underscore**
242
-
243
- ```javascript
244
- const data = library.map(book => {
245
- // The book argument is an individual model object in the collection
246
- const title = book.get('title');
247
- const row = Ti.UI.createTableViewRow({"title":title});
248
- return row;
249
- });
250
- // TableView object in the view with id = 'table'
251
- $.table.setData(data);
252
- ```
253
-
254
- ### Event Handling
255
-
256
- When working with Alloy Models and Collections, use the Backbone.Events `on`, `off` and `trigger` methods. For example:
257
-
258
- **Using events with collections**
259
-
260
- ```javascript
261
- const library = Alloy.createCollection('book');
262
- function event_callback (context) {
263
- const output = context || 'change is bad.';
264
- Ti.API.info(output);
265
30
  };
266
- // Bind the callback to the change event of the collection.
267
- library.on('change', event_callback);
268
- // Trigger the change event and pass context to the handler.
269
- library.trigger('change', 'change is good.');
270
- // Passing no parameters to the off method unbinds all event callbacks to the object.
271
- library.off();
272
- // This trigger does not have a response.
273
- library.trigger('change');
274
31
  ```
275
32
 
276
- Alloy Model and Collection objects don't support the Titanium `addEventListener`, `removeEventListener` and `fireEvent` methods.
277
-
278
- If you are using Alloy's Model-View binding mechanism, the Backbone add, change, destroy, fetch, remove, and reset events are automatically bound to an internal callback to update the model data in the view. Be careful not to override or unbind these events.
279
-
280
- If you want to fire or listen to multiple events, Backbone.js uses spaces to delimit its events in the event string; therefore, do **NOT** name any custom events with spaces.
281
-
282
- ## Alloy Data Binding
283
-
284
- ### Introduction
285
-
286
- When data in the collection changes, you may want to update the view simultaneously to keep information synchronized. This concept is known as data binding. Both Alloy and Backbone provide some mechanisms to bind model data to a view.
287
-
288
- ### Alloy Binding
289
-
290
- In Alloy, collection data can be synchronized to a view object, or a single model can be bound to a view component. Alloy monitors the Backbone add, change, destroy, fetch, remove, and reset events to update the data in the view.
291
-
292
- #### Collection-View Binding
293
-
294
- To enable collection-view binding, create a global singleton or controller-specific collection using the [Collection tag](https://titaniumsdk.com/docs/alloy/views) in the XML markup of the main view, then add the view object you want to bind data to. The following Titanium view objects support binding to a Collection:
295
-
296
- | View Object | Since Alloy version | Add data binding attributes to... | Repeater Object to map model attributes to view properties |
297
- | -------------- | ------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------ |
298
- | ButtonBar | 1.1 | `<Labels>` | `<Label/>` |
299
- | CoverFlowView | 1.1 | `<Images>` | `<Image/>` |
300
- | ListView | 1.2 | `<ListSection>` | `<ListItem/>` |
301
- | Map Module | 1.4 | `<Module module="ti.map" method="createView">` | None, model attributes will be used as params for createAnnotation() directly. |
302
- | Picker | 1.5 | `<PickerColumn>` or `<Column>` | `<PickerRow/>` or `<Row/>` |
303
- | ScrollableView | 1.1 | `<ScrollableView>` | `<View/>` May contain children view objects. |
304
- | TableView | 1.0 | `<TableView>` | `<TableViewRow/>` May contain children view objects. |
305
- | TabbedBar | 1.1 | `<Labels>` | `<Label/>` |
306
- | Toolbar | 1.1 | `<Items>` | `<Item/>` |
307
- | View | 1.0 | `<View>` | Any view object except a top-level container like a Window or TabGroup |
308
-
309
- You need to specify additional attributes in the markup, which are only specific to collection data binding. The only mandatory attribute is `dataCollection`, which specifies the collection singleton or instance to render. Note that you can only add these attributes to specific XML elements (refer to the table above).
310
-
311
- * `dataCollection`: specifies the collection singleton or instance to bind to the table. This is the name of the model file for singletons or the ID prefixed with the controller symbol ('$') for instances.
312
-
313
- * `dataTransform`: specifies an optional callback to use to format model attributes. The passed argument is a model and the return value is a modified model as a JSON object.
314
-
315
- * `dataFilter`: specifies an optional callback to use to filter data in the collection. The passed argument is a collection and the return value is an array of models.
316
-
317
- * `dataFunction`: set to an arbitrary identifier (name) for a function call. Use this identifier to call a function in the controller to manually update the view. This is not a declared function in the controller. This attribute creates an alias to access the underlying binding function, which is part of the Alloy data-view binding framework.
318
-
319
- Next, create a repeater object (refer to the table above) and place it inline with the view object with the `dataCollection` attribute, or place it in a separate view and use the `Require` tag to import it.
320
-
321
- To map model attributes, enclose the attribute with curly brackets or braces ('{' and '}'). You can map more than one attribute to a repeater object's property. For example, to assign the Label.text property to the model's title and author attributes, use this notation: `<Label text="{title} by {author}" />.` For more complex transformations, use the `dataTransform` callback to create a custom attribute.
322
-
323
- In the controller code of the repeater object, you can use the special variable `$model` to reference the current model being iterated over. This variable is present only in data bound controllers and is a reference to the currently bound model. For example, to get the title attribute of the current model, use `$model.title` to access it.
324
-
325
- > **⚠️ ⚠️ Warning**
326
- > **IMPORTANT:** When using Alloy's data binding in a view-controller, you **MUST** call the `$.destroy()` function when closing a controller to prevent potential memory leaks. The `destroy` function unbinds the callbacks created by Alloy when the collection-view syntax is used. For example:
327
- >
328
- > ```javascript
329
- > $.win.addEventListener("close", () => {
330
- > $.destroy();
331
- > });
332
- > ```
333
- >
334
- > For global singletons, to properly release them you should also remove event handlers with `off()` and set the reference to null:
335
- >
336
- > ```javascript
337
- > $.win.addEventListener("close", () => {
338
- > $.destroy();
339
- > Alloy.Collections.book.off();
340
- > Alloy.Collections.book = null;
341
- > });
342
- > ```
343
-
344
- #### Collection-View Binding Example
345
-
346
- The following example demonstrates how to add basic collection-view binding to an application. The example binds a collection of album models to a ScrollableView. In the ScrollableView, each model has its own view, which displays the album cover, title of the album and the artist. The `artist` and `title` attributes are bound to a Label object and the `cover` attribute is bound to an ImageView object.
347
-
348
- 1. Add the `<Collection>` tag as a child of the `<Alloy>` tag.
349
-
350
- **app/views/index.xml**
351
-
352
- ```xml
353
- <Alloy>
354
- <Collection src="album" />
355
- </Alloy>
356
- ```
357
-
358
- 2. Next, add the view object(s) you want to bind the data to. In this example, data will be bound to a ScrollableView object.
359
-
360
- **app/views/index.xml**
361
-
362
- ```xml
363
- <Alloy>
364
- <Collection src="album" />
365
- <Window backgroundColor="white" onClose="cleanup">
366
- <ScrollableView></ScrollableView>
367
- </Window>
368
- </Alloy>
369
- ```
370
-
371
- 3. Add the `dataCollection` attribute to the appropriate view object. Assign this attribute to the collection you want to use. For a ScrollableView object, add the attribute to the `<ScrollableView>` tag. The element to add the attribute to depends on which view object you want to bind data to.
372
-
373
- **app/views/index.xml**
374
-
375
- ```xml
376
- <Alloy>
377
- <Collection src="album" />
378
- <Window backgroundColor="white" onClose="cleanup">
379
- <ScrollableView dataCollection="album"></ScrollableView>
380
- </Window>
381
- </Alloy>
382
- ```
383
-
384
- 4. Next, create your repeater object and add model attributes. Enclose the model attributes with curly brackets or braces ('{' and '}'). For a ScrollableView, the repeater object can be a View object with additional children objects. The repeater object depends on which view object you are using.
385
-
386
- **app/views/index.xml**
387
-
388
- ```xml
389
- <Alloy>
390
- <Collection src="album"/>
391
- <Window backgroundColor="white" onClose="cleanup">
392
- <ScrollableView dataCollection="album">
393
- <View layout="vertical">
394
- <ImageView image="{cover}" />
395
- <Label text="{title} by {artist}" />
396
- </View>
397
- </ScrollableView>
398
- </Window>
399
- </Alloy>
400
- ```
401
-
402
- 5. In the controller, call the Collection's `fetch()` method to initialize the collection and sync any stored models to the view. Remember to call the `$.destroy()` method when you close the controller to prevent memory leaks.
403
-
404
- **app/controllers/index.js**
405
-
406
- ```javascript
407
- $.index.open();
408
- Alloy.Collections.album.fetch();
409
-
410
- function cleanup() {
411
- $.destroy();
412
- }
413
- ```
414
-
415
- The application is now setup for basic collection-view binding. When any new data is added to the collection, the ScrollableView will be updated with the new data.
416
-
417
- #### Model-View Binding
418
-
419
- To bind a single model to a component, create a global singleton or controller-specific model using the [Model tag](https://titaniumsdk.com/docs/alloy/views) in the XML markup of the main view and map the model attribute to the view component. To map the attribute to the view component, prefix the model name or id to the attribute, then enclose it with curly brackets or braces ('{' and '}').
420
-
421
- To do complex transformations on the model attributes, extend the model prototype with a `transform()` function. It should return the modified model as a JSON object.
422
-
423
- **app/models/album.js**
33
+ `columns` describes the schema. The adapter creates the table on first use; later schema changes require [migrations](./MODELS_ADVANCED.md). `extendModel` and `extendCollection` add behavior and must return their supplied class. Preserve the method's dynamic `this`; an arrow would change it.
424
34
 
425
35
  ```javascript
426
- exports.definition = {
427
- config: {}, // model definition
428
- extendModel(Model) {
429
- _.extend(Model.prototype, {
430
- transform() {
431
- const transformed = this.toJSON();
432
- transformed.artist = transformed.artist.toUpperCase();
433
- return transformed;
434
- }
435
- });
436
- return Model;
437
- }
438
- };
36
+ const notes = Alloy.createCollection('note');
37
+ notes.fetch();
38
+ const note = Alloy.createModel('note', { body: 'Write the docs', done: 0 });
39
+ note.save();
40
+ notes.add(note);
439
41
  ```
440
42
 
441
- A global singleton instance is a single instance of a particular model that is available for use anywhere in your application. When using global instances, they will be in memory for the duration of your application unless you manually release them. The process of manually releasing them should include:
442
-
443
- * If any controllers are using data binding that relies on the global instance, they should call their own destroy() function: `$.destroy()`
444
- * Any other event handlers added to the global instance should be removed with the [off()](http://backbonejs.org/#Events-off) function
445
- * Set the reference of the model to null: `Alloy.Models.nameOfModel = null;`
446
-
447
- Note that you need to call the `$.destroy()` function when closing the controller to prevent potential memory leaks. The `destroy` function unbinds the callbacks created by Alloy when the model-view syntax is used.
43
+ `fetch()` reads and `save()` writes through the adapter. They are network operations only if the adapter implements networking. Create an independent collection with `Alloy.createCollection`; declare a shared singleton with `<Collection src="note" />`, then access `Alloy.Collections.note`. Reading a missing JavaScript property alone does not create it.
448
44
 
449
- #### Model-View Binding Example
450
-
451
- The example below demonstrates how to bind a model to view components in the XML markup. Notice that each attribute is prefixed with the model's name and enclosed with braces.
45
+ ## Bind a collection to a list
452
46
 
453
47
  ```xml
48
+ <!-- app/views/index.xml -->
454
49
  <Alloy>
455
- <Model src="settings"/>
456
- <Window backgroundColor="white" onClose="cleanup">
457
- <View layout="vertical">
458
- <Label text="Text Size" />
459
- <Slider value="{settings.textsize}" max="5" min="1"/>
460
- <Label text="Bold"/>
461
- <Switch value="{settings.bold}" />
462
- <Label text="Italics"/>
463
- <Switch value="{settings.italics}" />
464
- </View>
50
+ <Collection src="note" />
51
+ <Window id="index">
52
+ <ListView defaultItemTemplate="noteRow">
53
+ <Templates>
54
+ <ItemTemplate name="noteRow">
55
+ <Label bindId="body" />
56
+ </ItemTemplate>
57
+ </Templates>
58
+ <ListSection dataCollection="note" dataFilter="onlyOpen" dataTransform="forRow">
59
+ <ListItem body:text="{body}" />
60
+ </ListSection>
61
+ </ListView>
465
62
  </Window>
466
63
  </Alloy>
467
64
  ```
468
65
 
469
- #### Collection Example
470
-
471
- The example below demonstrates how to display all book models in the collection by the author Mark Twain. It also demonstrates how to use each of the data binding attributes.
472
-
473
- **app/views/index.xml**
474
-
475
- ```xml
476
- <Alloy>
477
- <Collection src="book" />
478
- <Window class="container">
479
- <TableView dataCollection="book"
480
- dataTransform="transformFunction"
481
- dataFilter="filterFunction"
482
- dataFunction="updateUI"
483
- onDragEnd="refreshTable">
484
- <!-- Also can use Require -->
485
- <TableViewRow title="{title}" />
486
- </TableView>
487
- </Window>
488
- </Alloy>
489
- ```
490
-
491
- **app/controllers/index.js**
492
-
493
66
  ```javascript
494
- $.index.open();
495
-
496
- // Encase the title attribute in square brackets
497
- function transformFunction(model) {
498
- // Need to convert the model to a JSON object
499
- const transform = model.toJSON();
500
- transform.title = '[' + transform.title + ']';
501
- // Example of creating a custom attribute, reference in the view using {custom}
502
- transform.custom = transform.title + " by " + transform.author;
503
- return transform;
67
+ // app/controllers/index.js
68
+ function onlyOpen(collection) {
69
+ return collection.where({ done: 0 });
504
70
  }
505
71
 
506
- // Show only book models by Mark Twain
507
- function filterFunction(collection) {
508
- return collection.where({author:'Mark Twain'});
509
- }
510
-
511
- function refreshTable(){
512
- // Trigger the binding function identified by the dataFunction attribute
513
- updateUI();
72
+ function forRow(model) {
73
+ const row = model.toJSON();
74
+ row.body = row.body.toUpperCase();
75
+ return row;
514
76
  }
515
77
 
516
- // Trigger the synchronization
517
- const library = Alloy.Collections.book;
518
- library.fetch();
519
-
520
- // Free model-view data binding resources when this view-controller closes
78
+ Alloy.Collections.note.fetch();
521
79
  $.index.addEventListener('close', () => {
522
80
  $.destroy();
523
81
  });
524
- ```
525
-
526
- As the collection is updated, the view reflects the changes made to the models. If you want to suppress an update, specify `{silent: true}` in the `options` parameters when calling Backbone methods to change model data.
527
-
528
- ### Collection vs Model Data Binding
529
-
530
- You can bind both a collection of models or an individual model. To bind a model attribute the opening curly bracket is first followed by the model name and then the attribute. To bind a collection you add the `dataCollection` attribute to the container using the collection name as value. The generated code will then loop over the collection and add the child elements to the container for each model.
531
-
532
- ```xml
533
- <Alloy>
534
- <Model src="currentCategory" />
535
- <Collection src="book" />
536
- <Window>
537
- <!-- model data binding -->
538
- <Label text="{currentCategory.name}" />
539
-
540
- <!-- collection data binding -->
541
- <ScrollView dataCollection="book">
542
- <Label text="{title}" />
543
- </ScrollView>
544
- </Window>
545
- </Alloy>
546
- ```
547
-
548
- ### Global Singleton vs Local Instance
549
-
550
- In the above code snippet, the model and collection are global singletons under `Alloy.Models.currentCategory` and `Alloy.Collections.book`. You can also use local instances for the current controller by adding `instance="true"` as attribute. You also need to assign them an ID to reference them in the XML and controller.
551
-
552
- ```xml
553
- <Alloy>
554
- <Model src="currentCategory" instance="true" id="c" />
555
- <Collection src="book" instance="true" id="b" />
556
- <Window>
557
- <!-- model data binding -->
558
- <Label text="{$.c.name}" />
559
-
560
- <!-- collection data binding -->
561
- <ScrollView dataCollection="$.b">
562
- <Label text="{title}" />
563
- </ScrollView>
564
- </Window>
565
- </Alloy>
566
- ```
567
-
568
- ### Simple vs Complex Data Binding
569
-
570
- It's important to understand the difference between simple and complex data binding as they were implemented in unique ways which results in different behaviour.
571
-
572
- Simple data binding involves one model attribute where complex data binding involves a combination of strings (including white space) and model attributes or even multiple model attributes:
573
-
574
- ```xml
575
- <Alloy>
576
- <Model src="book">
577
- <Window>
578
- <!-- simple -->
579
- <Label text="{book.title}" />
580
-
581
- <!-- complex -->
582
- <Label text="Title: {book.title}" />
583
- <Label text="{book.author.name} {book.author.email}" />
584
- </Window>
585
- </Alloy>
586
- ```
587
-
588
- ### Backbone Binding
589
-
590
- The application can monitor Backbone events to trigger updates to the view.
591
-
592
- For instance, the code below demonstrates how to update a table when a model object is added to a collection by monitoring the add event:
593
-
594
- ```javascript
595
- library.on('add', e => {
596
- // custom function to update the content on the view
597
- updateFooView(library);
598
- });
599
- ```
600
-
601
- Another method is to selectively monitor changes. For instance, the code below demonstrates how to update data if a title changes in the collection:
602
-
603
- ```javascript
604
- library.on('change:title', e => {
605
- // custom function to update the content on the view
606
- updateFooView(library);
607
- });
608
- ```
609
-
610
- > **⚠️ ⚠️ Warning**
611
- > This only works if the Backbone method fires the change event and does not enable `{silent: true}` as an option.
612
-
613
- If you want to suppress an update, specify `{silent: true}` in the `options` parameters when calling Backbone methods to change model data. The data-bound view will not be updated to reflect the changes.
614
-
615
- ### Bind Deep Object Properties
616
-
617
- You can bind deep object properties:
618
-
619
- ```xml
620
- <Alloy>
621
- <Model src="book" />
622
- <Label text="{book.author.name}" />
623
- </Alloy>
624
- ```
625
-
626
- Before, you needed to use a transformer to create a reference like `authorName`.
627
-
628
- Before CLI 7.1.0, the only way to set object properties (e.g. `font.fontFamily` for a Label) was to use TSS. You can use dot notation in XML:
629
-
630
- ```xml
631
- <Alloy>
632
- <Model src="book" />
633
- <Label font.fontFamily="Roboto">Hello</Label>
634
- </Alloy>
635
- ```
636
-
637
- ### Use Models and Properties with Special Characters
638
-
639
- You can bind models and properties that use names with special characters like dashes and spaces. Simply wrap the names in square brackets and quotes like you'd do in JavaScript:
640
-
641
- ```xml
642
- <Alloy>
643
- <Model src="my-model">
644
- <Label text="['my-model']['my-property']" />
645
- </Alloy>
646
- ```
647
-
648
- ### Bind Multiple Models to the Same View
649
-
650
- You have the ability to bind multiple models to the same view:
651
-
652
- ```xml
653
- <Alloy>
654
- <Model src="a" />
655
- <Model src="b" />
656
- <Label text="{a.hello} {b.world}" />
657
- </Alloy>
658
- ```
659
-
660
- ### Define Transformations in the Model
661
-
662
- Since Alloy 1.8.1, all types of data binding will generate the following logic to determine what object will be bound to the view:
663
-
664
- ```javascript
665
- let t;
666
- if (_.isFunction(<dataTransform>)) { // only for collection binding
667
- t = <dataTransform>(model);
668
- } else if (_.isFunction(model.transform)) {
669
- t = model.transform();
670
- } else {
671
- t = model.toJSON();
672
- }
673
- $.myLabel.text = t.author.name;
674
- ```
675
-
676
- You'd extend a model with a `transform()` method as such:
677
-
678
- ```javascript
679
- exports.definition = {
680
- // config
681
- extendModel(Model) {
682
- _.extend(Model.prototype, {
683
- transform() {
684
- const t = this.toJSON();
685
- t.titleCaps = t.title.toUpperCase();
686
- return t;
687
- }
688
- });
689
- return Model;
690
- }
691
- };
692
- ```
693
-
694
- > **⚠️ ⚠️ Warning**
695
- > The `transform` method must return **all** bound properties, not just the transformed ones. Until Alloy 1.8.1, simple collection data binding did not require this and automatically fell back to the model attributes.
696
-
697
- ### Tips and Tricks
698
-
699
- #### Lazy Transformation
700
-
701
- The advantage of defining transformations in the model is that you don't need to repeat them in every controller. A possible disadvantage is that everywhere you bind the model all transformations are computed where you might only need some.
702
-
703
- You can handle this using `Object.defineProperty()`. Its `get` callback will only be called when the transform key is actually requested:
704
-
705
- ```javascript
706
- const moment = require('alloy/moment');
707
-
708
- exports.definition = {
709
- extendModel(Model) {
710
- _.extend(Model.prototype, {
711
- transform() {
712
- const model = this;
713
- const t = this.toJSON();
714
-
715
- Object.defineProperty(t, 'dateFormatted', {
716
- get() {
717
- return moment(t.date).format('LLLL');
718
- }
719
- });
720
-
721
- return t;
722
- }
723
- });
724
- return Model;
725
- }
726
- };
727
- ```
728
-
729
- #### Populating a Model After Data Binding
730
-
731
- When Alloy compiles your views and controllers, the generated view code precedes your controller code. Any models you define for data binding in the XML will also be created at that point. Just like you call `fetch()` to populate the collection, you do the exact same thing for the model.
732
-
733
- **index.xml**
734
-
735
- ```xml
736
- <Alloy>
737
- <Model src="book" instance="true" id="current" />
738
- <Window>
739
- <Label text="{book.title}" />
740
- </Window>
741
- </Alloy>
742
- ```
743
-
744
- **index.js**
745
-
746
- ```javascript
747
- $.current.fetch({
748
- id: Ti.App.Properties.getString('currentBook')
749
- });
750
-
751
82
  $.index.open();
752
83
  ```
753
84
 
754
- > **⚠️ ⚠️ Warning**
755
- > With the release of CLI 7.1.0, values passed in at creation of a view can be used as values in TSS and XML. For example, if the **foo** property was passed in at creation it can be used on a label:
756
- >
757
- > ```xml
758
- > <Alloy>
759
- > <Label text="$.args.foo" />
760
- > </Alloy>
761
- > ```
85
+ `dataCollection` names the collection; `{body}` supplies a model value to the list item. Additions and removals update rows. `dataFilter` returns the models to display; `dataTransform` reshapes each model for the view. Keep transformations inexpensive because they run per row on changes.
762
86
 
763
- ---
87
+ Bindings retain the view. Always call `$.destroy()` when disposing of a binding controller, alongside cleanup for listeners and timers described in [controllers](./CONTROLLERS.md#cleaning-up).
764
88
 
765
- For sync adapters, custom adapters, migrations, plain Backbone usage, and the Backbone version migration (0.9.2 → 1.1.2 / 1.3.3), continue with [MODELS_ADVANCED.md](MODELS_ADVANCED.md).
89
+ Source: [models and collections](https://titaniumsdk.com/docs/alloy/models.md). The singleton wording is corrected against released Alloy 3.0.1; explicit declaration is required.