読者です 読者をやめる 読者になる 読者になる

Umi Uyuraのブログ

Titaniumを使ったスマートフォンアプリ開発を中心に、プログラミング関連の作業ログ。

Alloy Modelの学習・その3(Properties Adapter)

Alloy Titanium

引き続き、Alloy Modelを深ぼってます。

umi-uyura.hatenablog.com

標準で用意されているSync Adapterには、SQLite用のSQL Adapterの他に、Titanium.App.Propertiesを使うProperties Adapterがあります。

※以前はもう一つ、Mobile Web用にlocalStorage adapterというのがあったようですが、Alloy 1.5.0で非推奨になってしまったようです。

Alloy Model、特にData Bindingを使う場面としては、SQLiteとの組み合わせで使うことの方が多い気がしますが、アプリのちょっとした設定を保持しておくのにTitanium.App.Propertiesを使うこともあるので、せっかくなので試しておくことにしました。

今回作るもの

設定画面で使う用途を想定して、1画面にいくつか入力項目があるもの、ということで、単純に名前・性別・国籍を登録しておく画面という、あまり実用性のないものになりました。

すべてテキスト入力だとつまらないので、性別だけOptionDialogを使って選択式にしています。

Android

f:id:umi-uyura:20160224234453p:plain f:id:umi-uyura:20160224234503p:plain

iOS

f:id:umi-uyura:20160224234513p:plain f:id:umi-uyura:20160224234524p:plain

ソースは umi-uyura/AlloyModelStudyProps にあがっているものです。

プロジェクト作成

例によってCLIでプロジェクト作成。

$ titanium create --type app --id com.example.titanium.alloymodelstudyprops --name AlloyModelStudyProps --platforms iphone,android --url http://www.example.com --workspace-dir .
$ alloy new AlloyModelStudyProps

これをベースに、今回もUIはJade & Stylusに、FokkeZB/UTiL/xp.ui を使っています。

モデル作成

上記の画面通り、以下のようなテーブルにします。

内容 カラム
ID id String
名前 name String
性別 gender String
国籍 nationality String

これをもとに alloy generate コマンドを使ってモデルを生成。

$ alloy generate model settings properties id:string name:string gender:integer nationality:string

今回想定している設定画面の場合は複数レコードが発生することはないため、レコードを識別する id は不要な気がしますが、Data Binding(というよりはBackbone?)の仕組み上、キーとなる属性が必要なようです。キーとなる属性がない場合、設定を更新しようとしたときに該当レコードが見つけられず、新しいレコードが作られてしまいます。

生成されたモデルを、最終的に以下のようにしました。

app/models/settings.js

exports.definition = {
  config: {
    columns: {
        "id": "string",
        "name": "string",
        "gender": "string",
        "nationality": "string"
    },
    defaults: {
      "id": "settingsId",
      "name": "",
      "gender": "",
      "nationality": ""
    },
    adapter: {
      type: "properties",
      collection_name: "settings",
      idAttribute: "id"
    }
  },
  extendModel: function(Model) {
    _.extend(Model.prototype, {
      // extended functions and properties go here
    });

    return Model;
  },
  extendCollection: function(Collection) {
    _.extend(Collection.prototype, {
      // extended functions and properties go here

      // For Backbone v1.1.2, uncomment the following to override the
      // fetch method to account for a breaking change in Backbone.
      /*
      fetch: function(options) {
        options = options ? _.clone(options) : {};
        options.reset = true;
        return Backbone.Collection.prototype.fetch.call(this, options);
      }
      */
    });

    return Collection;
  }
};

加えたのは config.defaults で、特に id には何か初期値を入れておかないと(つまりあらかじめキーを登録しておく)、先ほど述べたレコードが見つからない状態となってしまうようです。

画面とData Binding

今回もスタイルはソースを参照してもらうとして、Viewの index.jade は以下のようにしました。

app/views/index.jade

Alloy
  Model(src="settings")/
  NavigationWindow(module="xp.ui")
    Window.container(title="Alloy Model Study: Properties", onOpen="doOpen")
      View.line
        Label.label Name:
        TextField#textName.textfield(value="{settings.name}")
      View.line
        Label.label Gender:
        TextField#textGender.textfield(value="{settings.gender}", onClick="doGenderClick")
      View.line
        Label.label Nationality:
        TextField#textNationality.textfield(value="{settings.nationality}")
      View.controll
        Button#saveButton(onClick="doSaveClick") Save

前回のData Bindingと少し異なるのは、設定情報は1レコードでCollectionは不要なため、 <Alloy> タグ直下に記述するBindingする対象に関して、 <Model> タグで指定してみました。

各TextFieldにData Bindingする項目を設定し、これをもとにコントローラ側も実装。

app/controllers/index.js

var settings = Alloy.Models.settings;

function doOpen() {
  settings.fetch();
}

function doSaveClick(e) {
  var name = $.textName.getValue();
  var gender = $.textGender.getValue();
  var nationality = $.textNationality.getValue();

  settings.save({
    name: name,
    gender: gender,
    nationality: nationality
  });
}

...

Viewの open イベントで Model.fetch() してデータを読み込み、画面に配置したSaveボタンのクリック時に Model.save() してデータを保存しています。

Modelオブジェクト単独を扱っているため、Collectionから該当レコードを検索する処理がないこともあり、簡潔に書くことができました。

Appcelerator Titanium Smartphone App Development Cookbook - Second Edition

Appcelerator Titanium Smartphone App Development Cookbook - Second Edition