
Everything You Wanted to Know About Titanium Models and Collections
But for some reason they were afraid to ask.
Models are quite an important part of the application, because without data, nowhere.
In this article I will try to cover in as much detail as possible all aspects of the use of models in the MVC framework for the development of mobile applications Appcelerator Titanium.
If you have not tried contacting the models, then I hope this article saves you a couple of kilometers of nerves.
So, the first thing you should know when working with models in Titanium is that they are based on models and collections from Backbone. This means, firstly, you can use all the properties and methods described in the Backbone documentation; secondly, it will not be superfluous to first get to know her if you have not already done so.
Just in case, I will focus on terminology: a model is a single entity, a collection is a set of similar models.
Collections also inherit Underscore.js methods to make life easier for the developer. For example, the .map method
You can create a model in two equivalent ways: using Appcelerator Studio or manually.
Manually, you can create a special format file in a folder/ app / models / (which, in fact, will be done by the studio for you):
If you use the help of the studio, just call the context menu of the project and select the item “New -> Alloy Model”. When creating a dialog box will prompt you to select the type of adapter: localStorage, properties or sql. Adapter types are described below.
All you need to describe in this file for the basic functionality is the config block. It contains the data schema and type of synchronization adapter. This block should contain the following fields:
For example, we create a books model. To do this, create in the folder/ app / models / books.js file:
Here we have a model with two text fields: the name of the book and the author. Both fields default to "-". So far, everything is simple.
The sql adapter type indicates that when trying to get data, the model using the built-in adapter will try to connect to the SQLite database on the device and get data from the books table.
Own properties and methods in the model can be added as follows:
The same goes for collections. If you added your own methods to extendModel, they will be available on the model, but the collection does not, and vice versa.
There are two ways to access a model / collection:
In this case, the model will be available immediately everywhere, in all controllers. If it is already declared in one, then in the other, a call to the Alloy.Models.instance method will return a link to this declared model. An example is the User model, it can be everywhere alone.
Similarly for collections.
You can create a local link using the Alloy.createModel method . Then this model will be available only inside the controller where it is created. The method is a factory, pass the model name (file name minus .js) and parameters to it. And that’s all.
Similarly for collections.
Markup elementmust be a direct descendant. And it should have the src attribute with the value "model-file-name-minus-.js". Then the singleton of this model in the Alloy.Models namespace will be available in the controller:
This element also has an instance attribute. If it is true, then a link to the model will be created (local, available only within one controller). By the way, in this case, the model will not be accessible in the Alloy.Models namespace, it will need to be accessed by id:
Similarly for collections.
Finally we got to the section that was promised in the Create section. To work with models, it is not enough just to describe the data schema. You also need to connect them to something. This connection is the synchronization adapter.
An adapter is an implementation of Backbone.sync. Since the most common task is CRUD operations on a remote server (well, personally from my experience), by default the Backbone.sync method makes RESTful JSON requests to the addresses that you specify in the Model.urlRoot and Collection.url properties. This is the official documentation. In practice, in order to get a sense of models / collections, it is very convenient to use the restapi adapter, which I will talk about a little later. In the meantime, back to the official documentation.
Adapters can be of four types:
If the idAttribute key is not defined in the adapter section of the adapter, Alloy will generate the alloy_id field in your table and will use it as the primary key.
Pay attention to the db_file and db_name config fields (in the "Creation" section). Here they are important.
Unlike other types, in this method, Backbone.Collection.fetch can take a whole line of SQL query:
That is, if you want a simple query - pass the object with the query key in the parameters, but want a complex one - pass both the request and the parameters.
By the way, you can still pass the id key. In this case, the adapter itself will understand that you want to use the WHERE id =? .. constraint
If your database is not SQLite, then you can create your own adapter and do anything with the data. To do this, create an adapter file in the app / assets / alloy / sync or app / lib / alloy / sync directory, for example, myAdapter.js, and then specify the name of this file in the model config in adapter.type, that is, “myAdapter”.
Actually this file should export three functions:
If you need to receive data from a remote server, and you don’t want to create your own adapter, there is a wonderful restapi adapter that is not included in the number of built-in ones, but does its job (RESTful JSON requests) with a bang.
Minimum required settings - URL field in the config:
Of course, these are not all the available settings; for a complete list, see the documentation. And what else is important in this adapter is that the fetch method in it accepts a dictionary with three possible fields:
So, that’s all you need to know in order to be able to work with models in Titanium at a basic level. This topic is somewhat broader, for example, I deliberately omitted here a description of the migration process between different versions of the database, data binding, the use of models without Alloy, and also work with SQLite. I hope to fill all these gaps in the next article, stay tuned.
This article is based on a) official documentation; b) own experience of using models in Alloy. If among the habrasociety there are people who understand this issue better than me and see errors or inaccuracies, please, comment, discuss.
Models are quite an important part of the application, because without data, nowhere.
In this article I will try to cover in as much detail as possible all aspects of the use of models in the MVC framework for the development of mobile applications Appcelerator Titanium.
If you have not tried contacting the models, then I hope this article saves you a couple of kilometers of nerves.
Backbone.js
So, the first thing you should know when working with models in Titanium is that they are based on models and collections from Backbone. This means, firstly, you can use all the properties and methods described in the Backbone documentation; secondly, it will not be superfluous to first get to know her if you have not already done so.
Just in case, I will focus on terminology: a model is a single entity, a collection is a set of similar models.
Important: Titanium uses Backbone version 0.9.2, so some methods from the Backbone documentation may not be implemented.
Underscore.js
Collections also inherit Underscore.js methods to make life easier for the developer. For example, the .map method
Creature
You can create a model in two equivalent ways: using Appcelerator Studio or manually.
Manually, you can create a special format file in a folder
Model Description File Format
exports.definition = {
config : {
// схема данных
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// расширение Backbone.Model
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
// расширение Backbone.Collection
});
return Collection;
}
}
If you use the help of the studio, just call the context menu of the project and select the item “New -> Alloy Model”. When creating a dialog box will prompt you to select the type of adapter: localStorage, properties or sql. Adapter types are described below.
All you need to describe in this file for the basic functionality is the config block. It contains the data schema and type of synchronization adapter. This block should contain the following fields:
- columns : a dictionary describing the fields of the model. The key is the name of the field, the value is the type. Types like in SQLite: string, varchar, int, tinyint, smallint, bigint, double, float, decimal, number, date, datetime and boolean
- defaults : the same dictionary as columns, but now the values are the default field values if one of them is not defined during synchronization
- adapter : this object contains two fields:
- type : type of sync adapter
- collection_name : name of the collection. May differ from model name. You will use the value of this field to create a collection.
- idAttribute : primary key
For example, we create a books model. To do this, create in the folder
Example created model
exports.definition = {
config: {
"columns": {
"title": "String",
"author": "String" // если тип адаптера sql, то здесь можно еще SQLite keywords добавлять
},
"defaults": {
"title": "-",
"author": "-"
},
"adapter": {
"type": "sql",
"collection_name": "books",
"idAttribute" : "title",
"db_file" : "db_books", // название базы данных, с которой нужно работать. По умолчанию _alloy_
"db_name" : "books.sqlite", // название файла базы относительно каталога /app/assets. Если не указано, то создастся файл [имя_базы].sqlite
}
}
}
Here we have a model with two text fields: the name of the book and the author. Both fields default to "-". So far, everything is simple.
The sql adapter type indicates that when trying to get data, the model using the built-in adapter will try to connect to the SQLite database on the device and get data from the books table.
Own properties and methods in the model can be added as follows:
Model Extension Example
exports.definition = {
config : {
// схема данных
},
extendModel: function(Model) {
_.extend(Model.prototype, {
// расширение Backbone.Model
customProperty: 'book',
customFunction: function() {
Ti.API.info('Привет, я книга');
},
});
return Model;
}
}
The same goes for collections. If you added your own methods to extendModel, they will be available on the model, but the collection does not, and vice versa.
Using
There are two ways to access a model / collection:
- Creating a global singleton
- By creating a local link
- By specifying in XML markup if you are using Alloy
Global singleton
In this case, the model will be available immediately everywhere, in all controllers. If it is already declared in one, then in the other, a call to the Alloy.Models.instance method will return a link to this declared model. An example is the User model, it can be everywhere alone.
Similarly for collections.
Local link
You can create a local link using the Alloy.createModel method . Then this model will be available only inside the controller where it is created. The method is a factory, pass the model name (file name minus .js) and parameters to it. And that’s all.
Similarly for collections.
XML
Markup element
XML
Controller
var drama = Alloy.Models.book;
drama.set('title', 'Дальше живите сами');
drama.set('author', 'Джонатан Троппер');
This element also has an instance attribute. If it is true, then a link to the model will be created (local, available only within one controller). By the way, in this case, the model will not be accessible in the Alloy.Models namespace, it will need to be accessed by id:
XML
Controller
var drama = $.myBook;
drama.set('title', 'Дальше живите сами');
drama.set('author', 'Джонатан Троппер');
Similarly for collections.
Sync Adapters
Finally we got to the section that was promised in the Create section. To work with models, it is not enough just to describe the data schema. You also need to connect them to something. This connection is the synchronization adapter.
An adapter is an implementation of Backbone.sync. Since the most common task is CRUD operations on a remote server (well, personally from my experience), by default the Backbone.sync method makes RESTful JSON requests to the addresses that you specify in the Model.urlRoot and Collection.url properties. This is the official documentation. In practice, in order to get a sense of models / collections, it is very convenient to use the restapi adapter, which I will talk about a little later. In the meantime, back to the official documentation.
Adapters can be of four types:
- sql
- properties
- localStorage (not used since version alloy 1.5.0, so we won’t consider it)
- your type
SQL
If the idAttribute key is not defined in the adapter section of the adapter, Alloy will generate the alloy_id field in your table and will use it as the primary key.
Pay attention to the db_file and db_name config fields (in the "Creation" section). Here they are important.
Unlike other types, in this method, Backbone.Collection.fetch can take a whole line of SQL query:
Query string in .fetch ()
var library = Alloy.createCollection('book');
// Название таблицы - это collection_name из конфига
var table = library.config.adapter.collection_name;
// простой запрос
library.fetch({query:'SELECT * from ' + table + ' where author="' + searchAuthor + '"'});
// prepared statement
library.fetch({query: { statement: 'SELECT * from ' + table + ' where author = ?', params: [searchAuthor] }});
That is, if you want a simple query - pass the object with the query key in the parameters, but want a complex one - pass both the request and the parameters.
By the way, you can still pass the id key. In this case, the adapter itself will understand that you want to use the WHERE id =? .. constraint
id
myModel.fetch({id: 123});
// то же самое, что
myModel.fetch({query: 'select * from ... where id = ' + 123 });
properties
If your database is not SQLite, then you can create your own adapter and do anything with the data. To do this, create an adapter file in the app / assets / alloy / sync or app / lib / alloy / sync directory, for example, myAdapter.js, and then specify the name of this file in the model config in adapter.type, that is, “myAdapter”.
Actually this file should export three functions:
- module.exports.beforeModelCreate (config) (optional) - the method, as the name implies, is executed before creating the model. The parameters passed the config of this model. Here, for example, you can add baseUrl to the request address. Returns a modified config object
- module.exports.afterModelCreate (optional) - accepts two parameters: the brand-new newly created Backbone.Model class and the model file name
- module.exports.sync - implementation of the Backbone.sync method. It should return data
restapi
If you need to receive data from a remote server, and you don’t want to create your own adapter, there is a wonderful restapi adapter that is not included in the number of built-in ones, but does its job (RESTful JSON requests) with a bang.
Minimum required settings - URL field in the config:
Example model with restapi adapter
exports.definition = {
config: {
"URL": "http://example.com/api/modelname",
//"debug": 1,
"adapter": {
"type": "restapi",
"collection_name": "MyCollection",
"idAttribute": "id"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {});
return Collection;
}
}
Of course, these are not all the available settings; for a complete list, see the documentation. And what else is important in this adapter is that the fetch method in it accepts a dictionary with three possible fields:
- data request parameters
- success callback for successful request
- error callback for error
Conclusion
So, that’s all you need to know in order to be able to work with models in Titanium at a basic level. This topic is somewhat broader, for example, I deliberately omitted here a description of the migration process between different versions of the database, data binding, the use of models without Alloy, and also work with SQLite. I hope to fill all these gaps in the next article, stay tuned.
This article is based on a) official documentation; b) own experience of using models in Alloy. If among the habrasociety there are people who understand this issue better than me and see errors or inaccuracies, please, comment, discuss.