FOAM Cheat Sheet (long form)

Models

Model/class definition:

CLASS({

  package: ‘com.google.project’,

  name: ‘MyModel’,

  extendsModel: ‘com.google.project.MyBaseModel’,

  traits: [

    ‘com.google.project.MyFirstTrait’,

    ‘com.google.project.MyFirstSecondTrait’,

  ],

  requires: [

    ‘foam.ui.DetailView’,

    ‘com.google.project.MyOtherModel’,

  ],

  imports: [‘myOtherModelExportedProperty’],

  exports: [‘myModelExportedProperty’],

  constants: {

     CONSTANT1: value,

     ...

  },

  properties: [

    …

  ],

  methods: [

    …

  ],

  templates: [

    …

  ],

  actions: [

    …

  ],

  listeners: [

    …

  ]

});

Properties

Properties are data members on instances.

Name only; properties collection:

properties: [

  ‘myPropertyName’,

  …

],

Typed according to property’s model; property definition:

  {

    model_: ‘StringProperty’,

    name: ‘str’,

    documentation: function() {/*

      Multiline <i>documentation</i> for $$DOC{.}.

    */},

    defaultValue: ‘Hello world’,

  }

Typed according to “type” annotation; property definition:

  {

    type: ‘com.google.project.User’,

    name: ‘user’,

    factory: factory() { return this.User.create(); },

  }

Defaults

defaultValue -- Static value parsed when model is built.

defaultValueFn -- Function returns default value; function runs every time value is looked up and has not been set to something else.

factory -- Function returns default value; function runs once when instance is create if and only if no other value was injected at creation time.

Dynamic Get and/or Set

Caveat: Custom getters and setters are very low-level.

Getter; within property definition:

getter: function() { return this.op(this.leftOperand, this.rightOperand); }

Setter; within property definition:

setter: function(value) { return typeof value !== ‘undefined’ ? value : ‘’; }

(Most of the Basic) Property Types

IntProperty, FloatProperty, BooleanProperty, StringProperty, ArrayProperty, StringArrayProperty, ViewFactoryProperty, StringEnumProperty, ReferenceProperty, ReferenceArrayProperty

Custom property types can be constructed by creating a model FooProperty that extends Property, or FooArrayProperty that extends ArrayProperty, etc.

Methods

Methods are member functions on instances.

Name and implementation only; methods collection:

methods: {

  addAndMultiply: function(x, y, z) { return (x + y) * z; },

  …

}

Additional information; methods collection:

methods: [

  {

    name: ‘addAndMultiply’,

    documentation: ‘First add first two parameters, then multiply by the third.’,

    code: function(x, y, z) { return (x + y) * z; },

  },

  …

]

Listeners

Listeners are member functions pre-bound to instances. Use them as callback functions that will be passed around in the system, but expect to run with the correct “this” value.

Name and implementation only; methods collection:

Listeners collection:

listeners: [

  {

    name: ‘onClick’,

    documentation: ‘Respond to DOM click events on this HTML view.’,

    code: function(event) { … },

  },

  …

]

Actions

Actions are user-initiated actions that can be performed on instances.

Actions collection:

actions: [

  {

    name: ‘play’,

    label: ‘Play Video’,

    help: ‘Play the video for this post’,

    iconUrl: ‘http://www.example.com/play_icon.png’,

    documentation: ‘Play the video associated with this instance.’,

    action: function() { … },

  },

  …

]

Caveat: Action implementations are called the “action”, not the “code” (as in methods and listeners).

DAOs

Data Access Objects (DAOs) are an interface for data storage. Sinks are interfaces for receiving objects.

interface Sink {

   optional void put(obj) /* Called back when data is sent to the sink. */

   optional void remove(obj) /* Called back when data is removed from the sink. */

   optional void error() /* Called back when anything goes wrong during sink operation. */

   optional void eof() /* Called back when a sequence of puts or removes completes. */

}

interface DAO {

  void put(obj, opt_sink) /* Invoke to store an object; optionally put to sink once data is put to DAO. */

  void remove(query, opt_sink) /* Invoke to delete (an) object(s) from store; optionally remove from sink after removing from DAO. */

  void find(query, sink) /* Look up by primary key; put result to sink */

  Future<sink> select(sink) /* Put all objects in DAO to sink. Future resolves with passed-in sink after operation is complete. */

  Future<sink> update(expression) /* TODO(markdittmer): Document this. */

  void listen(sink) /* Listen to all sinkable operations on this DAO. */

  void pipe(sink) /* Short-hand for select(sink); listen(sink). */

  void unlisten(sink) /* Unhook listener from DAO. */

  DAO where(query) /* Construct decorated DAO that only contains objects matching query. */

  DAO limit(count) /* Construct decorated DAO that only contains the first count objects. */

  DAO skip(count) /* Construct decorated DAO that skips the first count objects. */

  DAO orderBy(...comparators) /* Construct decorated DAO that stores objects in order described by comparators. */

}

functions as sinks; function called back on put.

MLangs

EasyDAO

HTML Views

Template Syntax

{{javascriptExpression}} -- Insert HTML-escaped Javascript expression.

{{{javascriptExpression}}} -- Insert as-is Javascript expression.

<%= complexJavascriptExpression %> -- Identical to {{{javascriptExpression}}}, except provide support for more complex cases such as:

    <%= (function() { var value; … return value; })() %>

%%viewProperty{ args } -- Construct a child view of this.viewProperty.

$$dataProperty{ args } -- Construct a child view of this.data.dataProperty.

<% inlineJavascript %> -- Inject inline Javascript in template output function.

Simple Example

within the templates collection:

function toHTML() {/*

  <!-- Use common view properties to layout outer tag. -->

  <{{this.tagName}} id=”{{this.id}}<%= this.classAttr() %>>

    <!-- Construct a child view of this.data.dataProperty -->

    $$dataProperty{ factory_: ‘com.google.package.DataPropertyView’ }

    <!-- Construct the default a child view of this.viewProperty -->

    %%viewProperty

    <%

      var bits = this.data.bits;

      var len = bits.length;

      for (var i = 0; i < len; i++) {

    %>

      <%= bits[i].name %>

    <% } %>

  </{{this.tagName}}>

*/},

function CSS() {/*

  my-tag-name.hidden { display: none; }

  …

*/}

CSS templates are installed into a document when at least one instance of the view is constructed. The toHTML template is used every time an instance of the view is to be rendered in an HTML document.

Calls to sub-templates

Declare with an opt_out, then your parameters:

function startHTML(opt_out, param) {/*

        <div class=”<%= param %>”>

*/}

Call with the implicit ‘out’:

function toHTML() {/*

<div>        <% this.startHTML(out, this.paramProp); %></div>

*/}