API Reference
rx Namespace
This contains the core reactive programming primitives. These are the core data structures:
ObsCell: observable cell base classSrcCell: a source cell, one that can be directly mutatedDepCell: a dependent cell, one whose value is some function of another observable cell
ObsArray: observable array base classSrcArray: a source array, one that can be directly mutatedDepArray: a dependent array, one whose value is some transformation of another observable array
ObsMap: observable object (map) base classSrcMap: a source object, one that can be directly mutatedDepMap: a dependent object, one whose value is some transformation of another observable object
Ev: an event node; serves as a pub-sub node for events of a certain type
Free functions
cell(value): return aSrcCellinitialized to the given value (optional; defaults toundefined)array(value[, diff]): return aSrcArrayinitialized to the given array (optional; defaults to[]) and the givendifffunction for computing/propagating the minimal set of change events (defaults torx.basicDiff()).bind(fn): given a 0-ary function, return aDepCellwhose value is bound to the result of evaluating that function. The function is immediately evaluated once, and each time it's evaluated, for any accesses of observables, theDepCellsubscribes to the corresponding events, which may subsequently trigger future re-evaluations.snap(fn): evaluate the given 0-ary function while insulating it from the enclosing bind. This will be evaluated just once and prevents subscriptions to any observables contained therein.asyncBind(init, fn): create an asynchronous bind. The givenfnis expected to callthis.record(f)up to at most one time at some point during its potentially asynchronous duration before callingthis.done(result). The call tothis.record(f)evaluatesfwhile recording the implicit subscriptions triggered by accesses to observables. (You can calldonefrom withinrecordbut the result won't be set on this cell until afterrecordfinishes.) The cell's initial value isinit.lagBind(lag, init, fn): same asbindbut waits a 500ms delay after a dependency changes (or after initialization) before theDepCellrefreshes. For the first 500ms, the cell's value isinit; you can set this to e.g.noSub(fn)if you want to immediately populate it with the result of evaluating your givenfn.postLagBind(init, fn): immediately evaluatesfn, which is expected to return a{val, ms}, wheremsindicates how long to wait before publishingvalas the new value of thisDepCell. Until the first published value, the cell is initialized toinit.reactify(obj, spec): mutates an object to replace the specified fields with ES5 getters/setters powered by an observable cell/array, and returns the object.specis a mapping from field name to{type, val}, wheretypeis'array'or'cell'andvalis an optional initial value.autoReactify(obj): mutates an object toreactifyall fields (specifyingarrayfor arrays andcellfor everything else), and returns the objectflatten(xs): given an array of either arrays, observable arrays, observable cells, or other elements, flatten them into one dependent array, which will be able to react to changes in any of the observables. It furthermore strips outundefined/nullelements (for convenient conditionals in the array).onDispose(callback): add a (0-ary) cleanup listener, which gets fired whenever the current (enclosing) bind is removed or refreshed. This is useful for proper resource disposal, such as closing a connection or removing an interval timer.skipFirst(f): wrap a 1-ary function such that the first invocation is simply dropped. This is useful for subscribing an event listener but suppressing the initial invocation at subscription time.autoSub(ev, listener): Subscribes a listener to an event but such that if this is called from within abindcontext, the listener will be properly cleaned up (unsubscribed) on context disposal. Returns the subscription ID.concat(arrays...): returns a dependent array that is the result of concatenating multipleObsArrays (efficiently maintained).cellToArray(cell[, diff]): given anObsCellof an array, return aDepArraythat issues the minimal set of change events by diffing the contents of the array to determine what has changed. Similar in mechanism toSrcArray.update.diffis an optional diff function (seeSrcArray.updatedocumentation) and defaults torx.basicDiff().basicDiff([key]): returns a diff function that takes two arrays and uses the given key function, which defaults torx.smartUidify, to efficiently hash-compare elements between the two arrays. Used byrx.cellToArray.smartUidify(x): returns a unique identifier for the given object. If the item is a scalar, then return its JSON string. If the item is an object/array/etc., create a unique ID for it, insert it (this is a standard "hashing hack" for JS) as a non-enumerable property__rxUid, and return it (or just return any already-existing__rxUid). I.e., this implements reference equality. Used byrx.basicDiff.lift(x[, spec]): convert an objectxcontaining regular non-observable fields to one with observable fields instead.specis a mapping from field name to either'cell','array', or'map', based on what kind of observable data structure we want. By default this is supplied byrx.liftSpec.liftSpec(x): given an objectx, return a spec forrx.liftwhere any field that is an array is to be stored in anrx.array, and otherwise in anrx.cell.transaction(f): run the given function in a transaction, during which updates to observables will not emit change events to their subscribers. Only once the transaction ends will all events be fired (at which time the state of the source cells will no longer be in flux, and thus a consistent view of the universe can always be maintained).
ObsCell members
get(): return current value of the cellonSet: the event that is fired after the value of the cell is changed. The event data is an array of two elements,[oldVal, newVal].
SrcCell members
set(x): set value of cell toxand return old value ofx- inherits
ObsCell
DepCell members
- inherits
ObsCell disconnect: unsubscribes this cell from its dependencies and recursively disconnects all nested binds; useful for manual disposal ofbinds
ObsArray members
at(i): return element atiall(): return array copy of all elementsraw(): return raw array of all elements; this is unsafe since mutations will violate the encapsulated invariants, but serves as a performance escape hatch aroundall()length(): return size of the arraymap(fn): returnDepArrayof given function mapped over this arrayonChange: the event that is fired after any part of the array is changed. The event data is an array of three elements:[index, added, removed], whereindexis the index where the change occurred,addedis the sub-array of elements that were added, andremovedis the sub-array of elements that were removed.indexed(): return aDepArraythat mirrors this array, but whosemapmethod passes in the index as well. The mapper function takes(x,i)wherexis the current element andiis a cell whose value always reflects the index of the current element.
SrcArray members
SrcArray([xs[, diff]]): constructor that initializes the content array toxs(note: keeps a reference and does not create a copy) and the diff function forupdatetodiff(defaults torx.basicDiff()).splice(index, count, additions...): replacecountelements starting atindexwithadditionsinsert(x, i): insert valuexat indexiremove(x): find and remove first occurrence ofxremoveAt(i): remove element at indexipush(x): appendxto the end of the arrayput(i, x): replace elementiwith valuexreplace(xs): replace entire array with raw arrayxsupdate(xs[, diff]): replace entire array with raw arrayxs, but apply thediffalgorithm to determine the minimal set of changes for which to emit events. This enables flexible updating of the array, representing arbtirary transformations, while at the same time minimizing the downstream recomputation necessary (particularly DOM manipulations).- inherits
ObsArray
DepArray members
- inherits
ObsArray
ObsMap members
get(k): return value associated with keykall(): return raw object copyonAdd: the event that is fired after an element is added. The event data is[key, newVal].onRemove: the event that is fired after an element is removed. The event data is[key, oldVal].onChange: the event that is fired after a key's value is changed. The event data is[key, oldVal, newVal].
SrcMap members
put(k, v): associate valuevwith keykand return any prior value associated withkremove(k): remove the entry associated at keykupdate(map): update the currentSrcMap's contents to those of the given JS objectmap, triggering any necessaryremoves andputs- inherits
ObsMap
DepMap members
- inherits
ObsMap
Ev members
sub(listener): subscribes a listener function for events from this event node and returns a unique ID for this subscription, which can be used as the handle by which to unsubscribe later. The listener takes a single argument, whose type depends on the event, and is called every time an event is fired on this event node.pub(data): publish an event, described by the data indata.datais what will be passed to all the subscribed listeners.unsub(subscriptionId): detaches a listener from this event.
rx.rxt Namespace
This contains the template DSL constructs. Main thing here is the tag function, which is what constructs a DOM element.
Free functions
mktag(tag): returns a tag function of the given tag name. The various tags likedivandh2are simply aliases; e.g.,div = mktag('div'). Tag functions themselves take(attrs, contents), both optional, whereattrsis a JavaScript object of HTML attributes and/or special attributes andcontentsis an array (ObsArrayor regularArray) of child nodes (either raw elements,RawHtml, or jQuery objects) and/or strings (for text nodes). You can also pass in a singular such node without the array. The function returns an instance of the specified element wrapped in a jQuery object. See alsospecialAttrsbelow for more on special attributes.importTags([dest]): populate the global namespace (or thedestobject if given) with the tag symbols, so you don't need haverxtall over your templates. Useful for quickly throwing something together.rawHtml(html): returns aRawHtmlwrapper for strings that tags won't escape when rendering; example:div {}, [rawHtml('<span>hello</span>')]rxt.cast(...): two forms:rxt.cast(opts, types): convenience utility for use in preparing arguments for a component.optsis the arguments object mapping, andtypesis an object mapping fields ofoptsto eithercellorarray.castreturns a copy ofoptsbut with the fields casted based on the specified desiredtypes(yielding observable cells and arrays).rxt.cast(data, type): lift the given datum to the given type; acts as identity function if data is already of the proper type
rxt.cssify(props): (deprecated: set thestyleproperty directly to a JSON object instead of using this so as to usejQuery.css, which is smarter about interpreting the given values) convenience utility for programmatically constructing strings suitable for use as astyleattribute. Takes an object mapping camelCase versions of style property names and values that are either strings (which are put in verbatim), numbers (which are written as pixels), ornull/undefined(which omits that property altogether).rxt.smushClasses(classes): convenience utility for programmatically constructing strings suitable for use as aclassattribute. Takes an array of strings orundefineds (useful for conditionally including a class), and filters out thenull/undefined.- Tags:
p,br,ul,li,span,anchor,div,input,select,option,label,button,fieldset,legend,section,header,footer,strong,h1,h2,h3,h4,h5,h6,h7
jQuery plug-in
rx(property): lazily create (or take the cached instance) of a cell whose value is maintained to reflect the desired property on the element.propertycan be'checked','focused', or'val'. Returns the cell.
Special attributes
Special attributes are handled differently from normal. The built-in
special attributes are primarily events like click:
button {click: -> console.log('hello')}, 'Hello'
Special attributes are really just a convenient short-hand for running the handler functions after constructing object. The above example is equivalent to:
$button = button 'Hello'
$button.click -> console.log('hello')
The built-in special attributes available include:
init: which is a 0-ary function that is run immediately upon instantiation of the element.style: automatically transforms the given value withcssifyif it's not a stringclass: automatically transforms the given value withsmushClassesif it's not a stringevents like
click,focus,mouseleave,keyup,load, etc.,: these are available for all jQuery events. The handlers are similar to those you would pass to a jQuery event method—they take a jQuery event and return false to stop propagation—but the context is the jQuery-wrapped element instead of the raw element. The full list:blurchangeclickdblclickerrorfocusfocusinfocusouthoverkeydownkeypresskeyuploadmousedownmouseentermouseleavemousemovemouseoutmouseovermouseupreadyresizescrollselectsubmittoggleunload
specialAttrs: an object mapping special attribute names to the functions
that handle them. When an element specifies a special attribute, this
handler function is invoked. The handler function takes (element, value,
attrs, contents), where:
elementis the element being operated onvalueis the value of this special attribute forelementattrsis the full map of attributes forelementcontentsis the content/children forelement(which can be a string,RawHtml, array,ObsCell, orObsArray)
So for instance, we can create a special attribute drag that just
forwards to the jQuery [jdragdrop] plug-in:
rxt.specialAttrs.drag = (elt, fn, attrs, contents) -> elt.drag(fn)
and then use it like so in your templates:
div {class: 'block', drag: -> $(this).css('top', e.offsetY)}