The map is the primary arbiter of execution flow in the application; but it is not enough on its own. Applications also need models, views and controllers to make them complete.
Models and stores work exactly as they do in vanilla Sencha Touch.
Views perform two basic functions in AppMaps:
At each choice point (each blob on the map) the system instantiates whichever views are necessary.
If we go back to one of the application maps used in the previous section, each of these types of views can be seen as useful.
At the first blob, there's no previous selections to show; but the user can choose an album, so a view which claims to let the user select an album is useful. At the second, the developer certainly needs to provide a view which lets the user select a song from the album; they may also wish to provide a view which displays some details of the album. For the third blob, the developer should certainly provide a view which displays details of the song the user just selected, since there is no further choice to be made.
Note that there is neither a 1:1 correspondence between blobs and views, nor arrows and views; an arrow can be connected to up to two views, one of each type, whereas a blob can consist of a potentially unlimited number of views.
Views are implemented as functions which construct a Sencha Touch component (usually a descendent of Ext.Panel, Ext.List or Ext.DataView). The function is passed an AppMaps object which the view can use to interact with the AppMaps system in general (more on this below), the name of the edge it is representingm and the style which is to be applied. Use the code below as a template.
Be aware: You need to explicitly apply the styling to your view yourself; this will be rectified in future.
vfn = function(appmaps, name, style) { var configoptions = { ... }; Ext.apply(configoptions, util.styles.sencha(style); return new Ext.Panel(configoptions); };
This function is called when the view is created, rather than when it is displayed. You should not initialise your actual display here; if you need to do anything before the view is displayed, you should attach an onOpen attribute to the object you return.
var configoptions = { ... onOpen: function(ctx) { // Do something more interesting than this this.update(ctx.someSelection.text); } }
The ctx parameter passed to onOpen is a JavaScript object which contains the objects corresponding to the selections made by the user thus far. For example, the object corresponding to the selection made for the edge {cat:Category} is in ctx.cat. (For more details on the way selections work, see below). In onOpen, use 'this' to refer to the Sencha component, as you'd expect.
If your view is providing choices to the user (and allowing the user to traverse one of the arrows in the map) then you need to notify the AppMaps runtime when such a selection is made. The selection itself is represented by an arbitrary JavaScript object which is opaque as far as the run-time is concerned; this object is placed in the context (the ctx variable passed to onOpen) for the use of other views and of controllers (see below).
To notify the system of a selection, use the the swallowObject method appmaps object as passed to the factory function (which will still be available in the view due to closure). The swallowObject method takes three parameters; the name of the edge (which was passed originally in the name parameter to the factory function), the type of object being passed back, and the JavaScript object to store under this name:
appmaps.swallowObject(name, "TypeOfObject", { field: "value" });
This will generally go into an event listener. So, for example, in an Ext.List derived view, there could be something like this:
listeners: { selectionChange: function(sm, records) { // check whether we have a selection if (records && records.length > 0) { aut.swallowObject(name, "SomeObjectOrOther", records[0]); } } }
Finally, you need to register each view with AppMaps, using the registerView method:
util.viewfactory.registerView(type, viewname, fn, consuming)
The first parameter is the type of object which the view lets the user select; if it does not permit the user to make selections, set it to null. The second is a human-readable view name which is displayed in logs and debugging information, and used in stylesheets. The third is the constructor function (as laid out above). The fourth is a JavaScript object of name:type pairs which correspond to the edges for which this can act as a details view. If this does not perform this role, set it to null or to the empty object.
This is best illustrated by examples. Looking back again at the map:
To register a view for the first blob, which would just display a list of albums, the registration would look something like:
util.viewfactory.registerView("Album", "AlbumListView", fn, {});
To register a view which displays the last "Song" selection, register a view something like:
util.viewfactory.registerView(null, "AlbumListView", fn, {s: "Song"});
In AppMaps, the main controller of your application should not be linked to specific user interface elements as it is in, for example, a vanilla Sencha Touch or a Cocoa application. Instead, you associate controller actions with a set of selections the user must make; once all the selections a controller is interested in have been made, the controller action is called.
A controller action is just a function, although it's advisable to wrap it in an object to avoid polluting your namespace. The prototype of your controller action should look something along the lines of:
controllerAction: function(appmaps, ctx) { // do something clever with ctx here }
The two parameters are the same as are passed to the onOpen method on views; the first is an appmaps object which allows controller actions to simulate user input; the latter is a JavaScript object which contains "name: object" mappings for selections users have already made.
Be aware: 'this', in the controller action does not refer to the controller. In fact, it is best to avoid using 'this' in controller actions at all. This will hopefully be rectified in future.