appcelerator titanium alloy tipstricks by fokke zandbergen
DESCRIPTION
Appcelerator Titanium Alloy tipstricks by Fokke Zandbergen This is not his official account I just re uploaded it here to make it easier for people to find and learn. you can follow him : http://fokkezb.nl/TRANSCRIPT
July 23rd, 2013London TitaniumAlloy Tips & Tricks
FOKKE ZANDBERGENapp imagineer
������������������������������������������ ����� ���������������� �����������
Alloy Tips & Tricks
Compilation processNot your mother's MVC
TSS
XML
Views
+
=Definition
=
Models Controllers
Assets
config.json
Compilation processNot your mother's MVC
Definition
=
Models Controllers
Assets
config.json
JS
Compilation processNot your mother's MVC
Definition
=
Models Controllers
Assets
config.json
JSCommonJS
Compilation processNot your mother's MVC
Collections
Syn
c
Store
Models Controllers
Assets
config.json
JSCommonJS
Compilation processNot your mother's MVC
Collections
Syn
c
Store
Models Controllers
Assets
config.json
JSCommonJS
Compilation processNot your mother's MVC
Collections
Syn
c
Store
Models Controllers
Assets
config.jsonAlloy.CFG
JSCommonJS
Compilation processNot your mother's MVC
Collections
Syn
c
Store
Models Controllers
Assets
config.jsonAlloy.CFG
JSCommonJS
Compiled controllersThe first might be last
function Controller() {! // Controller functions function myFoo() { alert("Says bar"); } var $ = this; var exports = {};
! // Parsed XML view $.__views.label = Ti.UI.createLabel({ id: "label" }); $.__views.label && $.addTopLevelView($.__views.label);
_.extend($, $.__views);
! // Controler code $.myLabel.text = "Hello London!"; exports.myFoo = myFoo;
_.extend($, exports);}
var Alloy = require("alloy"), Backbone = Alloy.Backbone, _ = Alloy._;module.exports = Controller;
Compiled controllersAbout $, exports and this
$.label === $.__views.label === this.label;exports.label === undefined;
exports.foo = 'bar';$.bar = 'foo';
Inline code
function myFunction() {! $.label === $.__views.label;! this.label === exports.label === undefined; !! $.foo === exports.foo;! this.foo = undefined;
exports.bar === undefined;}
Functions
Titanium Studio ShortcutsBe lazy
⇧⌘C New controller + view + style⇧⌘Y New widget ⇧⌘M New model⇧⌘I New migration
More: http://go.fokkezb.nl/ttshortcuts
Installing Alloy from GithubLiving on the edge
sudo npm install -g git://github.com/appcelerator/alloy.git
Rollback to stable
sudo npm uninstall -g alloysudo npm install -g alloy
* Drop "sudo" on Windows
Hacking AlloyHave the last word
/app/assets/alloy.js/app/assets/alloy/backbone.js/app/assets/alloy/underscore.js/app/assets/alloy/sync/sql.js/app/themes/myTheme/assets/alloy/CFG.js
• The SQLite sync adapter is not compatible with Backbone.js 1.x• Make sure you sync config.json changes to your CFG.js files
Alloy.isTablet = function() { return (Ti.Platform.displayCaps.platformWidth > 800);}
app/alloy.js
.. or go wild and overwrite
Extend via app.js
WPATHWhich Path | | Widget Path
function WPATH(s) { var index = s.lastIndexOf("/"); var path = -1 === index ? "myWidget/" + s : s.substring(0, index) + "/myWidget/" + s.substring(index + 1); return path;}
app/widgets/myWidget/assets/foo.pngResources/myWidget/foo.png
app/widgets/myWidget/assets/one/two/three.pngResources/one/two/MyWidget/three.png
Examples
• Assets and libs the same• Place stuff in platform specific iphone, android folders• Place stuff in the images folder
Custom sync adapters.. for widget models
/app/widgets/my.widget/assets/alloy/sync/myAdapter.js
Drop your sync adapter in:
exports.definition = { config: { adapter: { type: 'my.widget/myAdapter' } }};
Use in widget models:
/Resources/alloy/sync/my.widget/myAdapter.js
It will end up in:
/app/widgets/my.widget/models/myModel.js
All-in-one widgetKnow the 'name'Bundle a group of widgets as one
<Widget src="myMenus" /><!-- default: widget(.js) --><Widget src="myMenus" name="slide" /><Widget src="myMenus" name="drawer" />
* Available since Alloy 1.1
Specific controller per context
<Widget src="myList" /><!-- default: widget(.js) --><Widget src="myList" name="tab" /><Widget src="myList" name="window" /><Widget src="myList" name="view" />
Alloy.createWidget("nl.fokkezb.tweetsView", "widget", { id: "myWidget", foo: "bar"});
Styleable & Themable widgetsThe . and # gameSet ID and class of view components to same, globally unique value
<Alloy>! <Label id="myWidgetLabel" class="myWidgetLabel" /></Alloy>
Apply defaults styles using classes
".myWidgetLabel": {! color: 'red'}
"#myWidgetLabel": {! color: 'blue'}
Instruct developers using your widget to override using IDs
More: http://go.fokkezb.nl/alloytssprio (widgets missing)
__parentSymbolWho's your daddy?
<Alloy>! <Window>! ! <Widget src="randomBgColor" />! </Window></Alloy>
__parentSymbol.backgroundColor = '#'+Math.floor(Math.random()*16777215).toString(16);
app/widgets/randomBgColor/controllers/widget.js
Stateful widgetsKeeping track
<Alloy>! <Window class="container" layout="vertical">! ! <Widget src="stateful" />! ! <Widget src="stateful" />! </Window></Alloy>
var state = require(WPATH('state'));$.instanceCounter.text = state.counter++;
exports.counter = 0;
app/widgets/stateful/assets/state.js
app/widgets/stateful/controllers/widget.js
app/views/index.xml
Data Binding3 flavours<Model id="instance" src="myModel" instance="true" /><Label id="a" text="{field}" /><Label id="b" text="{singleton.field}" /><Label id="c" text="{$.instance.field}" />
var $model = arguments[0] ? arguments[0]["$model"] : null;$.instance = Alloy.createModel("myModel");
$.__views.a.text = "undefined" != typeof $model.__transform["field"] ? $model.__transform["field"] : $model.get("field");
var __alloyId1 = function() { $.b.text = _.isFunction(Alloy.Models.singleton.transform) ? Alloy.Models.singleton.transform()["field"] : Alloy.Models.singleton.get("field");};Alloy.Models.singleton.on("fetch change destroy", __alloyId1);
var __alloyId2 = function() { $.c.text = _.isFunction($.instance.transform) ? $.instance.transform()["field"] : $.instance.get("field");};$.instance.on("fetch change destroy", __alloyId2);
Bind an existing modelWorkarounds
function openDetail(e) {! var model = col.get(e.rowData.modelId);! model.__transform = myTransformer(model); // model.toJSON();! Alloy.createController('detail', {! ! '$model': model! });}
function openDetail(e) {! var detailModel = col.get(e.rowData.modelId);! detailModel.__transform = myTransformer(detailModel);! detailModel.transform = function() { return this.__transform; };! Alloy.Models.detailModel = detailModel;! Alloy.createController('detail');}
Pre-setting a singleton
Emulating a dataCollection loop WARNING: No change listeners
Main controller switchingSkipping index.js
var Alloy = require("alloy"), _ = Alloy._, Backbone = Alloy.Backbone;Alloy.createController("index");
• Alloy always requires index.xml
app.js
// $.index.open();if (Ti.App.Properties.getBool('isLoggedIn', false)) { Alloy.createController("home");} else { Alloy.createController("login");}
index.js
<Alloy />
index.xml
Reset your app.tssClean slate
'Label[platform=android]': { // Instead of platform-dependent color: '#000' } 'Window': { // More common-sense default vs 'transparent' backgroundColor: '#fff' } 'Window[platform=android]': { // Never lightweight (deprecated) modal: false } 'TextField': { // More common-sense default vs un-styled borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED } 'ImageView[platform=ios]': { // Never show ugly temporary image preventDefaultImage: true }}
Discussion: http://go.fokkezb.nl/alloyreset
@import TSSOr the power of alloy.jmk
@import "reset.tss";
"Window": {! backgroundColor: 'black'}
Source: http://go.fokkezb.nl/alloyimport
task("pre:compile", function(event, logger) {! explodeImport(event, logger);}); task("post:compile", function(event, logger) {! implodeImport(event, logger);});
app/alloy.jmk
Jade 2 XMLBe lazy like David Bankier
<Alloy> <Window class="container"> <Label id="label" onClick="doClick">Hello, World</Label> </Window></Alloy>
Blog: http://go.fokkezb.nl/alloyjade
Alloy Window.container Label#label(onClick="doClick") Hello, World
app/views/index.jade
• No need for closing tags• Advanced templating• Advanced conditions
XML 2 TSSBe lazy like David Bankier
<Alloy> <Window class="container"> <Label id="label" onClick="doClick">Hello, World</Label> </Window></Alloy>
Source: https://github.com/dbankier/xml2tss
".container": {}".#label": {}
xml2tss index.xml ../styles/index.tss
• Will update existing TSS• Integrated in Alloy 1.2
Less TSSBe lazy like David Bankier
@primColor: "blue";
.bg (@color) { backgroundColor: $color}
".container" : { .bg($primColor);}
Source: https://github.com/dbankier/ltss
".container" : { backgroundColor: "blue"}
ltss index.ltss index.tss
Detecting AlloyUsing Alloy libs without Alloy
var isAlloy = (typeof ENV_TEST === 'boolean');
• Alloy constants like OS_IOS don't exist at run-time• They are replaced by TRUE|FALSE during compile• Code blocks that will never execute are removed• In Vanilla Titanium they will be undefined
var Alloy = require('alloy');Alloy.infect && Alloy.infect(this);
myLib.js or app.js (3.1+)
Source: http://go.fokkezb.nl/alloydetect
Wrapping Ti.UI.* components.. using widgets or CommonJS modules
<ImageView image="http://my.im/age.png" />
Before
<Widget src="ImageView" image="http://my.im/age.png" />
After:
<ImageView module="My.UI" image="http://my.im/age.png" />
Coming in Alloy 1.2:
• Pass on or intercept common parameters, functions and events
/app/widgets/ImageView/controllers/widget.js
require('My.UI').createImageView()
<ImageView ns="require('My.UI')" image="http://my.im/age.png" />
Simple, durable workaround:
Wrapping Ti.UI.* componentsPassing argumentsexports.setText = function (text) { $.myVew.text = text.toUpperCase(); }
_.each(['text', 'color'], function (pr) { var cam = pr[0].toUpperCase() + pr.substring(1); var get = exports['get' + cam] || ($['get' + cam] = function () { retur $.myVew[pr]; }); var set = exports['set' + cam] || ($['set' + cam] = function (val) { $.myVew[pr] = val; }); Object.defineProperty($, pr, { get: get, set: set });});
exports.applyProperties = function(properties) { properties = _.omit(properties, 'id', '__parentSymbol', '__itemTemplate', '$model'); var apply = {}; _.each(properties, function (val, pr) { ! var fn = 'set' + pr[0].toUpperCase() + pr.substring(1); ! exports[fn] ? exports[fn](val) : (apply[pr] = val); }); _.isEmpty(apply) || $.myVew.applyProperties(apply);}exports.applyProperties(arguments[0]);
• Looping _.keys($.myVew) would only give set properties• Add set/get on $ as so applyProperties can't find them• Define properties on $ as that's the final object• Filter Alloy properties as (__parentSymbol would give memory leak)
Wrapping Ti.UI.* componentsPassing functions
_.each(['resume', 'pause', 'hide'], function (fn) { if (!exports[fn]) { ! exports[fn] = $.myVew[fn]; }});
• Remember we already did setters and getters for properties
Wrapping Ti.UI.* componentsPassing events
exports.on = $.myVew.addEventListener;exports.off = $.myVew.removeEventListener;exports.trigger = $.myVew.fireEvent;
• For (widget) controllers onClick translates to .on('click')
<Widget src="ImageView" image="http://my.im/age.png" onClick="doClick" />
ResourcesMust reads
• Alloy docshttp://go.fokkezb.nl/alloydocs
• Backbone.js 0.9.2http://go.fokkezb.nl/bb092
• Underscore.jshttp://go.fokkezb.nl/undscore
• Moment.jshttp://go.fokkezb.nl/momentjs
• Alloy Google Grouphttp://go.fokkezb.nl/alloygroup
• Alloy Q&Ahttp://go.fokkezb.nl/alloyqa
• Alloy changeloghttp://go.fokkezb.nl/alloylog
• Alloy test appshttp://go.fokkezb.nl/alloytests
• Alloy compiler sourcehttp://go.fokkezb.nl/alloycompiler
• Alloy widgets @ AlloyLove.com• Twitter: #TiAlloy
http://go.fokkezb.nl/alloylinks
[email protected] @FokkeZB