PageRenderTime 9ms CodeModel.GetById 2ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/www/documentation.html

https://github.com/anthonybrown/backbone.epoxy
HTML | 795 lines | 663 code | 131 blank | 1 comment | 0 complexity | 81f5c78feafbdd6615916692650cffbc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4	<meta charset="utf-8">
  5	<title>Epoxy.js : Elegant Data Binding for Backbone : Documentation</title>
  6
  7	<meta http-equiv="X-UA-Compatible" content="IE=edge">
  8	<meta name="description" content="Epoxy is an elegant and extensible data binding library for Backbone.js designed to hook view elements directly to data models.">
  9	<meta name="author" content="Greg MacWilliam">
 10	<meta name="viewport" content="width=device-width, initial-scale=1">
 11	<meta name="apple-mobile-web-app-title" content="Epoxy.js">
 12	<meta name="application-name" content="Epoxy.js">
 13	
 14	<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
 15	<link rel="icon" href="favicon.ico" type="image/x-icon">
 16	<link href="style/reset.css" rel="stylesheet">
 17	<link href="style/screen.css" rel="stylesheet">
 18	<script type="text/javascript">
 19
 20	  var _gaq = _gaq || [];
 21	  _gaq.push(['_setAccount', 'UA-39215101-1']);
 22	  _gaq.push(['_trackPageview']);
 23
 24	  (function() {
 25	    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 26	    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 27	    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 28	  })();
 29
 30	</script>
 31</head>
 32<body>
 33	<div id="page">
 34		<div class="banner clearfix" role="banner">
 35			<p class="title"><span><b>Epoxy</b>.js</span> Elegant Data Binding for Backbone</p>
 36			<div class="download">
 37				<a href="js/backbone.epoxy.min.js" class="download-button">Download Epoxy 0.10.0</a>
 38				<p class="download-info">8k min, 2k gzip <i>|</i> <a href="https://github.com/gmac/backbone.epoxy">GitHub Full Source</a></p>
 39			</div>
 40		</div>
 41		<div class="navigation" role="navigation">
 42			<ul class="nav-main clearfix">
 43				<li><a href="index.html">About Epoxy.js</a></li>
 44				<li><a href="tutorials.html">Getting Started</a></li>
 45				<li class="active"><a href="documentation.html">Documentation</a></li>
 46			</ul>
 47			<div class="nav-toc">
 48				<div class="nav-toc-content">
 49					<b><a href="#model">Epoxy.Model</a></b>
 50					<ul>
 51						<li><b><a href="#model-extend">extend</a></b></li>
 52						<li><b><a href="#model-constructor">constructor</a></b></li>
 53						<li><a href="#model-add-computed">addComputed</a></li>
 54						<li><a href="#model-add-observable">addObservable</a></li>
 55						<li><a href="#model-clear-observables">clearObservables</a></li>
 56						<li><a href="#model-computeds">computeds</a></li>
 57						<li><a href="#model-destroy">destroy</a></li>
 58						<li><a href="#model-get">get</a></li>
 59						<li><a href="#model-get-copy">getCopy</a></li>
 60						<li><a href="#model-has-observable">hasObservable</a></li>
 61						<li><a href="#model-modify-array">modifyArray</a></li>
 62						<li><a href="#model-modify-object">modifyObject</a></li>
 63						<li><a href="#model-observable-defaults">observableDefaults</a></li>
 64						<li><a href="#model-remove-observable">removeObservable</a></li>
 65						<li><a href="#model-set">set</a></li>
 66					</ul>
 67			
 68					<b><a href="#view">Epoxy.View</a></b>
 69					<ul>
 70						<li><b><a href="#view-extend">extend</a></b></li>
 71						<li><b><a href="#view-constructor">constructor</a></b></li>
 72						<li><b><a href="#view-binding-context">binding context</a></b></li>
 73						<li><a href="#view-apply-bindings">applyBindings</a></li>
 74						<li><a href="#view-binding-handlers">bindingHandlers</a></li>
 75						<li><a href="#view-bindings">bindings</a></li>
 76						<li><a href="#view-binding-sources">bindingSources</a></li>
 77						<li><a href="#view-remove">remove</a></li>
 78						<li><a href="#view-remove-bindings">removeBindings</a></li>
 79					</ul>
 80			
 81					<b><a href="#binding-handlers">View Binding Handlers</a></b>
 82					<ul>
 83						<li><a href="#handler-attr">attr</a></li>
 84						<li><a href="#handler-checked">checked</a></li>
 85						<li><a href="#handler-classes">classes</a></li>
 86						<li><a href="#handler-collection">collection</a></li>
 87						<li><a href="#handler-css">css</a></li>
 88						<li><a href="#handler-disabled">disabled</a></li>
 89						<li><a href="#handler-enabled">enabled</a></li>
 90						<li><a href="#handler-events">events</a></li>
 91						<li><a href="#handler-html">html</a></li>
 92						<li><a href="#handler-options">options</a></li>
 93						<li><a href="#handler-options-default">optionsDefault</a></li>
 94						<li><a href="#handler-options-empty">optionsEmpty</a></li>
 95						<li><a href="#handler-text">text</a></li>
 96						<li><a href="#handler-toggle">toggle</a></li>
 97						<li><a href="#handler-value">value</a></li>
 98					</ul>
 99			
100					<b><a href="#binding-operators">View Binding Operators</a></b>
101					<ul>
102						<li><a href="#operator-all">all</a></li>
103						<li><a href="#operator-any">any</a></li>
104						<li><a href="#operator-format">format</a></li>
105						<li><a href="#operator-length">length</a></li>
106						<li><a href="#operator-none">none</a></li>
107						<li><a href="#operator-not">not</a></li>
108						<li><a href="#operator-select">select</a></li>
109					</ul>
110				</div>
111			</div>
112		</div>
113		<div class="main" role="main">
114			<h1>Documentation</h1>
115			
116			<div class="section">
117				<h2 id="model">Epoxy.Model</h2>
118			
119				<p>The Epoxy Model object extends <tt>Backbone.Model</tt>, providing a new model abstract to be extended into your application.</p>
120
121				<p>The Epoxy model introduces observable attributes on top of Backbone's native model attributes. Observable attributes are virtualized properties of the model: they may be <b>get</b> and <b>set</b> just like normal model attributes, and will trigger <tt>"change"</tt> events on the model when modified, however they do not exist within the model's <b>attributes</b> table, nor will they be saved with model data. Observable model attributes exist only in memory for the lifespan of a model instance. The goal of observable attributes is to provide an intermediary layer between a model's data and its display; allowing stateful view data (such as view selection states) to be managed within the model, yet not be retained by data stores.</p>
122
123				<p>Additionally, Epoxy's observable attributes may be <i>computed</i>. Computed attributes operate as accessors and mutators, where a computed attribute will <b>get</b> an assembled value derived from other model attributes, and will <b>set</b> one more more mutated values derived from an input. Computed observables bind themselves to their dependency model attributes and will update themselves in response to any of their dependencies changing, then in turn trigger their own <tt>"change:attributeName"</tt> event on the model.</p>
124			</div>
125			<div class="section">
126				<h3 id="model-extend">extend</h3>
127				<code>Backbone.Epoxy.Model.extend(properties, [classProperties])</code>
128				<p>Extends the <tt>Epoxy.Model</tt> constructor for use in your own implementation.</p>
129			</div>
130			
131			<div class="section">
132				<h3 id="model-constructor">constructor</h3>
133				<code>new Backbone.Epoxy.Model([attributes], [options])</code>
134				<p>Creates a new <tt>Epoxy.Model</tt> instance.</p>
135			</div>
136			
137			<div class="section">
138				<h3 id="model-add-observable">addObservable</h3>
139				<code>model.addObservable(name, value)</code>
140				<p>Adds an observable attribute to the model. Observable attributes are virtualized properties of the model: they may be <b>get</b> and <b>set</b> just like normal model attributes, and will trigger <tt>"change"</tt> events on the model when modified, however they do not exist within the model's <b>attributes</b> table, nor will they be saved with model data. Observable model attributes exist only in memory for the lifespan of a model instance. The goal of observable attributes is to provide an intermediary layer between a model's data and its display; allowing stateful view data (such as view selection states) to be managed within the model, yet not be retained by data stores.</p>
141
142				<p>Observable attributes may store any type of data, and will trigger normal <tt>"change:attributeName"</tt> events when set through the model's standard <b>set</b> method.</p>
143				
144				<p>Observable attributes storing object values (<tt>Object</tt> or <tt>Array</tt>) will trigger <tt>"change"</tt> events in response to changes in object composition, rather than object identity (this differs from the base Backbone Model, which will only trigger <tt>"change"</tt> events when a unique object instance replaces another within the model). Object comparison checks are performed using Underscore's <b>isEqual</b> method, which will compare the composition of objects and the contents of arrays. Performance should be considered when managing large objects.</p>
145				
146<pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model();
147model.addObservable("isSelected", false);
148alert( model.get("isSelected") );</code>	
149</pre>
150				<p>Use the <b><a href="#model-observable-defaults">observableDefaults</a></b> hash to automatically construct observables on your model instances.</p>
151			</div>
152			
153			<div class="section">
154				<h3 id="model-add-computed">addComputed</h3><br>
155				<code>model.addComputed(name, params) or...</code><br>
156				<code>model.addComputed(name, getter, [setter], [*deps])</code>
157				<p>Adds a computed observable attribute to the model. Computed attributes operate as accessors and mutators, where a computed attribute will <b>get</b> an assembled value derived from other model attributes, and will <b>set</b> one more more mutated values derived from an input. Computed observables bind themselves to their dependency attributes and will update themselves in response to any of their dependencies changing, then in turn trigger their own <tt>"change:attributeName"</tt> event on the model.</p>
158
159				<p id="model-computed-params">The <b>addComputed</b> method is called with an attribute name and a params object defining the following:</p>
160				
161				<ul>
162					<li><b>get:</b> <i>Required function; invoked in context of the model</i>. This getter function assembles its value based on other model properties (attributes, observables, or other computeds), then returns the generated value. Note that a getter function should always reference other model values using the model's <b>get</b> method (for <a href="#model-computed-deps">automatic dependency mapping</a>).</li>
163                    
164					<li><b>[deps]:</b> <i>Optional array</i>. An array of attribute names that the getter function depends on. This manual property mapping is only required if your getter contains unreachable values that would be missed by automatic dependency mapping (discussed below).</li>
165                    					
166					<li><b>[set]:</b> <i>Optional function; invoked in context of the model</i>. A mutator function which receives a raw input value, and returns an object defining new key/value pairs to be merged into the model. Computed observables declared without a <b>set</b> function are read-only.</li>
167				</ul>
168				
169				<p>Note that the <b>get</b> and <b>set</b> functions are invoked in the context of their parent model, so referencing <tt>this</tt> within their scopes refers to the model.</p>
170				
171<pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({price:100});
172model.addComputed("formattedPrice", {
173    deps: ["price"],
174    get: function() {
175        return "$"+ this.get("price");
176    },
177    set: function( value ) {
178        return {price: parseInt(value.replace("$", ""))}
179    }
180});
181
182alert( model.get("formattedPrice") ); // '$100'
183model.set("formattedPrice", "$150");
184alert( model.get("price") ); // 150</code>	
185</pre>
186				
187				<p><b id="model-computed-deps">Automatic Dependency Mapping</b></p>
188				<p>In the above example, <tt>["price"]</tt> is manually declared as a dependency of the computed getter (meaning the getter will need to update itself when <tt>"price"</tt> changes). While this manual declaration is a nice safety net, we could also exclude the <tt>"deps"</tt> param entirely in this case thanks to Epoxy's automatic dependency mapping.</p>
189				
190				<p>Automatic dependency mapping works using the <b>get</b> method wrapper of the <tt>Epoxy.Model</tt>. While generating a computed attribute's initial value, the <tt>Epoxy.Model</tt> registers all attribute names requested from <i>all</i> <tt>Epoxy.Model</tt> instances, and binds the computed attribute accordingly. Automatic mapping works great given the following:</p>
191				
192				<ul>
193					<li>All model references (the parent model, or others) are instances of <tt>Epoxy.Model</tt>.</li>
194					<li>All model attributes are accessed using their model's <b>get</b> method.</li>
195					<li>All <b>get</b> calls are free of conditional logic (keep reading...)</li>
196				</ul>
197				
198				<p>Regarding conditional <b>get</b> calls: this situation may create unreachable getters that cannot be automatically mapped. Consider the following BROKEN example:</p>
199				
200<pre>
201<code class="js">var model = new Backbone.Epoxy.Model({
202    shortName: "Luke",
203    fullName: "Luke Skywalker",
204    active: false
205});
206
207// BROKEN:
208model.addComputed("displayName", function() {
209    return this.get("active") ? this.get("fullName") : this.get("shortName");
210});</code>	
211</pre>
212				<p>See the error in the above example? The <tt>"fullName"</tt> and <tt>"shortName"</tt> attributes are accessed conditionally, therefore one will be unreachable while mapping dependencies. To fix this, we could either manually declare dependencies, or else <b>get</b> all dependencies as local variables prior to conditional logic, like so:</p>
213				
214<pre>
215<code class="js">// FIXED:
216model.addComputed("displayName", function() {
217    var fullName = this.get("fullName");
218    var shortName = this.get("shortName");
219    return this.get("active") ? fullName : shortName;
220});</code>	
221</pre>
222				<p>Use the <b><a href="#model-computeds">computeds</a></b> hash to automatically construct computed observables on your model instances.</p>
223			</div>
224			
225			<div class="section">
226				<h3 id="model-clear-observables">clearObservables</h3>
227				<code>model.clearObservables()</code>
228				<p>Removes all observable properties on the model and cleans up their bound events. Cleared observables will no longer exist on the model, so will no longer be accessible or trigger events. Be sure to call <b>clearObservables</b> when deprecating an Epoxy model without specifically calling its <b>destroy</b> method.</p>
229			</div>
230			
231			<div class="section">
232				<h3 id="model-computeds">computeds</h3>
233				<code>model.computeds</code>
234				<p>A hash table declaring computed observable attributes to be automatically added to a model instance by the constructor. Uses <b><a href="#model-add-computed">addComputed</a></b> to create observable attributes. Computed observables may be declared with a <a href="#model-computed-params">computed params</a> object, or as a getter function (uses <a href="#model-computed-deps">automatic dependency mapping</a>).</p>	
235<pre>
236<code class="js">var ComputedModel = Backbone.Epoxy.Model.extend({
237    defaults: {
238        firstName: "Luke",
239        lastName: "Skywalker"
240    },
241    computeds: {
242        fullNameParams: {
243            deps: ["firstName", "lastName"],
244            get: function() {
245                return this.get("firstName") +" "+ this.get("lastName");
246            },
247            set: function( value ) {
248                var first = value.split(" ")[0];
249                var last = value.split(" ")[1];
250                return {firstName: first, lastName: last};
251            }
252        },
253        fullNameGetter: function() {
254            return this.get("firstName") +" "+ this.get("lastName");
255        }
256    }
257});</code>
258</pre>
259			</div>
260			
261			<div class="section">
262				<h3 id="model-destroy">destroy</h3>
263				<code>model.destroy([options])</code>
264				<p>Override wrapper for the Backbone Model's native <b>destroy</b> method. This wrapper cleans up Epoxy model configuration, then defers to the Backbone Model's native <b>destroy</b> method. If you'd like to clean up a model without completely destroying it, use the <b>clearObservables</b> method.</p>
265			</div>
266			
267			<div class="section">
268				<h3 id="model-get">get</h3>
269				<code>model.get(attribute)</code>
270				<p>Override wrapper for the Backbone Model's native <b>get</b> method. This override allows basic model attributes and Epoxy observable/computed attributes to be accessed through a common API.</p>
271				<p>The Epoxy <b>get</b> method will first check for an observable attribute, then defers to the Backbone Model's native <b>get</b> method if no observable was found. Remember that an observable attribute overrides a native attribute with the same name, so be mindful of naming collisions.</p>
272			</div>
273			
274			<div class="section">
275				<h3 id="model-get-copy">getCopy</h3>
276				<code>model.getCopy(attribute)</code>
277				<p>Gets a model attribute value (native, observable, or computed), and performs a shallow copy on any non-primitive values returned. This is useful for getting copies of <tt>Object</tt> and <tt>Array</tt> values that you plan to modify outside of the model, then resubmit with changes (remember that <tt>"change"</tt> events only trigger for non-primitive values when their identity changes). The <b><a href="#model-modify-array">modifyArray</a></b> and <b><a href="#model-modify-object">modifyObject</a></b> methods may also be used to perform object changes internally within the model.</p>
278			</div>
279			
280			<div class="section">
281				<h3 id="model-has-observable">hasObservable</h3>
282				<code>model.hasObservable(attribute)</code>
283				<p>Returns <tt>true</tt> if the model has an observable or computed observable attribute with the specified name. Note that the Backbone Model's native <b>has</b> method is NOT modified by Epoxy, so will still only report on the presence of Backbone-native model attributes.</p>
284			</div>
285			
286			<div class="section">
287				<h3 id="model-modify-array">modifyArray</h3>
288				<code>model.modifyArray(attribute, arrayMethod, [*args])</code>
289				<p>Performs an internal update on a stored <tt>Array</tt> model attribute (native or observable) using a standard JavaScript array modifier (<tt>pop</tt>, <tt>push</tt>, <tt>reverse</tt>, <tt>shift</tt>, <tt>slice</tt>, <tt>sort</tt>, <tt>splice</tt>, and <tt>unshift</tt>), then triggers a change event for the modified model attribute. Invoke with the model attribute name to modify, a string of the array method name to call, and any additional arguments to be passed into the array method. Returns any results from the array method. Calling <b>modifyArray</b> on a non-array attribute will take no action.</p>
290				
291<pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({wordList:[]});
292model.modifyArray("wordList", "push", "deathstar");
293alert( model.get("wordList").length );</code>	
294</pre>
295			</div>
296
297			<div class="section">
298				<h3 id="model-modify-object">modifyObject</h3>
299				<code>model.modifyObject(attribute, objectProperty, value)</code>
300				<p>Performs an internal update on a stored <tt>Object</tt> model attribute (native or observable), then triggers a change event for the modified model attribute. Invoke with the model attribute name to modify, a property name to set on the object, and a value to set as the object property. Setting <tt>undefined</tt> to a property will delete it from the object. Returns the modified object. Calling <b>modifyObject</b> will only take action on model attributes with an assessed type of <tt>"object"</tt>.</p>
301				
302<pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({ wordsDict:{} });
303model.modifyObject("wordsDict", "deathstar", true);
304alert( model.get("wordsDict").hasOwnProperty("deathstar") );</code>	
305</pre>
306			</div>
307			
308			<div class="section">
309				<h3 id="model-observable-defaults">observableDefaults</h3>
310				<code>model.observableDefaults</code>
311				<p>A hash table declaring observable attributes to be automatically added to a model instance by the constructor. Uses <b><a href="#model-add-observable">addObservable</a></b> to create the specified observable attributes. After a model instance has been constructed, observable values are managed through the model's <b>get</b> and <b>set</b> methods. Any observable values declared as a function will be invoked while getting added to the model; this is useful for creating unique Object/Array values for each model instance.</p>
312<pre>
313<code class="js">var ComputedModel = Backbone.Epoxy.Model.extend({
314    observableDefaults: {
315        isSelected: false,
316        keysList: function() { return ["a", "b"]; }
317    }
318});</code>
319</pre>	
320			</div>
321			
322			<div class="section">
323				<h3 id="model-remove-observable">removeObservable</h3>
324				<code>model.removeObservable(attribute)</code>
325				<p>Removes an observable attribute by name, and cleans up all bound listeners. A removed observable property will no longer exist within the model, so may no longer be accessed or trigger events.</p>
326			</div>
327			
328			<div class="section">
329				<h3 id="model-set">set</h3>
330				<code>model.set(attributes, [options])</code>
331				<p>Override wrapper for the Backbone Model's native <b>set</b> method. This override allows basic model attributes and Epoxy observable/computed attributes to be accessed through a common API.</p>
332				<p>The Epoxy <b>set</b> method will first check for an observable attribute, then defers to the Backbone Model's native <b>set</b> method if no observable was found. Remember that an observable attribute overrides a native attribute with the same name, so be mindful of naming collisions.</p>
333			</div>
334			
335			<div class="section">
336				<h2 id="view">Epoxy.View</h2>
337
338				<p>The Epoxy View object extends <tt>Backbone.View</tt>, providing a new view abstract to be extended into your application.</p>
339
340				<p>The Epoxy View provides elegant and extensible hooks for binding a data source (<tt>Backbone.Model</tt> and/or <tt>Backbone.Collection</tt> instances) directly to DOM elements. When data attributes change, they will automatically trigger refresh of all bound view elements; seamlessly updating the view without requiring a complete render pass.</p>
341
342				<p>Also note that an Epoxy view may bind to a native <tt>Backbone.Model</tt> instance, or to an <tt>Epoxy.Model</tt> with specialized observable attributes. Because both model types operate with a common API, the Epoxy View does not depend on its <tt>Epoxy.Model</tt> counterpart to support model bindings. Therefore, you're free to exclude <tt>Epoxy.Model</tt> resources from your project if you just want view binding features.</p>
343			</div>
344			
345			<div class="section">
346				<h3 id="view-extend">extend</h3>
347				<code>Backbone.Epoxy.View.extend(properties, [classProperties])</code>
348				<p>Extends the <tt>Epoxy.View</tt> constructor for use in your own implementation.</p>
349			</div>
350			
351			<div class="section">
352				<h3 id="view-constructor">constructor</h3>
353				<code>new Backbone.Epoxy.View([options])</code>
354				<p>Creates a new <tt>Epoxy.View</tt> instance.</p>
355			</div>
356			
357			<div class="section">
358				<h3 id="view-binding-context">binding context</h3>
359				<code>{$model:model, $collection:collection, [*attributes]}</code>
360				<p>To establish bindings, an Epoxy view generates a <i>binding context</i> with routes pointing to all available <i>data sources</i> and their attributes. Data sources are instances of <tt>Backbone.Model</tt> and/or <tt>Backbone.Collection</tt> that provide themselves and their attributes to the view for binding. By default, an Epoxy view looks for two potential data sources: the view's <b>model</b> property, and its <b>collection</b> property. References to these data sources are automatically configured in the binding context as <tt>$model</tt> and <tt>$collection</tt>. Aliases to all <tt>$model</tt> attributes are also created.</p>
361				<p>Additional <tt>Model</tt> and <tt>Collection</tt> data sources may be added to the binding context using the <b><a href="#view-binding-sources">bindingSources</a></b> property.</p>
362			</div>
363			
364			<div class="section">
365				<h3 id="view-apply-bindings">applyBindings</h3>
366				<code>view.applyBindings()</code>
367				<p>Removes any existing view bindings, then applies all bindings defined within the view's <b>bindings</b> object. All bindings are established using the view's <b>$el</b> as the display target, and the view's <b>model</b>, <b>collection</b>, and/or <b>bindingSources</b> properties as the data sources (see <b><a href="#view-binding-context">binding context</a></b> and <b><a href="#view-binding-sources">bindingSources</a></b> for more information). A view with invalid display or data targets will apply no bindings. If the <b>bindings</b> object is a string, that string will be used as an attribute selector query for extracting bindings from the view's <b>$el</b> container.</p>
368
369				<p>The <b>applyBindings</b> method is automatically called by the view constructor <i>after</i> the view's <b>initialize</b> method runs. This allows the <b>initialize</b> step to make adjustments within the view prior to bindings being applied. You generally shouldn't need to call <b>applyBindings</b> manually.</p>
370
371				<p>Also note that view bindings are baked at the time they are applied. All relationships between data sources and the view are established during this binding step and can only be reconfigured by unbinding and rebinding the view.</p>
372			</div>
373			
374			<div class="section">
375				<h3 id="view-binding-handlers">bindingHandlers</h3>
376				<code>view.bindingHandlers</code>
377				<p>A hash table defining a view's custom binding handlers. Binding handlers are used to interchange model data with elements in the view. While Epoxy includes a <a href="#binding-handlers">core set</a> of basic binding handlers for managing an element's content and formatting, developers are encouraged to extend their views with customized binding handlers.</p>
378					
379				<p>To declare binding handlers, define a new property on the <b>bindingHandlers</b> hash with a params object defining <b>set</b> and <b>get</b> function properties:</p>
380
381<pre>
382<code class="js">var BindingView = Backbone.Epoxy.View.extend({
383    bindingHandlers: {
384        printList: {
385            set: function( $element, value ) {
386                $element.text( value.join(",") );
387            },
388            get: function( $element, value ) {
389                return $element.text().split(",");
390            }
391        }
392    }
393});</code>
394</pre>				
395				<ul>
396					<li><b>set:</b> <i>Required function, invoked in context of the binding</i>. This function is used to WRITE data from the model into the view. The <b>set</b> function receives two arguments: a jQuery representation of the bound element, and the model attribute value to be written into the view. The <b>set</b> function returns nothing.</li>
397					<li><b>[get]:</b> <i>Optional function, invoked in context of the binding</i>. This function is used to READ data from the view to be sent to the model. The <b>get</b> function receives two arguments: a jQuery representation of the bound element, and the current model attribute value to be changed (useful when modifying objects). The <b>get</b> function should return a value to replace the current bound model attribute. When modifying <tt>Object</tt> and <tt>Array</tt> values, be sure to make changes to a <i>copy</i> of the current value, then submit that back to the model.</li>
398				</ul>
399				
400				<!--p>Note that the <b>get</b> and <b>set</b> functions are invoked in the context of their parent view, so referencing <tt>this</tt> within their scopes refers to the view.</p-->
401				
402				<p>While declaring a display-only binding handler (one-way binding), you may declare its setter function directly on the <b>bindingHandlers</b> hash:</p>
403
404<pre>
405<code class="js">var BindingView = Backbone.Epoxy.View.extend({
406    bindingHandlers: {
407        printList: function( $element, value ) {
408            $element.text( value.join(",") );
409        }
410    }
411});</code>
412</pre>
413			</div>
414						
415			<div class="section">
416				<h3 id="view-bindings">bindings</h3>
417				<code>view.bindings</code>
418				<p>A hash declaring the view's element-to-attribute binding scheme, or a string defining an element attribute to query from the view's DOM. All bindings are established using the view's <b>$el</b> reference as the display target, and the view's <b>model</b> reference as the data target. A view missing its <b>$el</b> and/or <b>model</b> properties will apply no bindings.</p>
419				
420				<p>The bindings hash syntax keeps all binding declarations within the view. The <b>bindings</b> object declares a set of key/value pairs, where the key defines an element query, and the value defines the element's model bindings:</p>
421<pre>
422<code class="js">var BindingModel = Backbone.Model.extend({
423    defaults: {
424        firstName: "Luke",
425        lastName: "Skywalker"
426    }
427});
428	
429var BindingView = Backbone.Epoxy.View.extend({
430    model: new BindingModel(),
431    bindings: {
432        "input.first-name": "value:firstName,events:['keyup']",
433        "input.last-name": "value:lastName,events:['keyup']"
434    }
435});</code>
436</pre>
437				<p>Alternatively, you may choose to follow the popular convention of declaring bindings directly within the DOM using element attributes, at which time the <b>bindings</b> property should define the attribute name to query for. Epoxy specifies <tt>"data-bind"</tt> by default. All philosophical opinions aside, this technique works just as well as view-based declarations. Getting into philosophy, this method creates a bizarre (albeit handy) relationship between JavaScript mechanics and raw display. Ultimately, the choice is yours as to which method works best for your purposes.</p>
438
439<pre>
440<code class="js">var BindingModel = Backbone.Model.extend({
441    defaults: {
442        firstName: "Luke",
443        lastName: "Skywalker"
444    }
445});
446
447var BindingView = Backbone.Epoxy.View.extend({
448    el: "#binding-view"
449    model: new BindingModel(),
450    bindings: "data-bind"
451});
452
453&lt;div id="binding-view"&gt;
454    &lt;p&gt;First: &lt;input type="text" data-bind="value:firstName,events:['keyup']"&gt;&lt;/p&gt;
455    &lt;p&gt;Last: &lt;input type="text" data-bind="value:lastName,events:['keyup']"&gt;&lt;/p&gt;
456&lt;/div&gt;</code>
457</pre>
458			</div>
459			
460			<div class="section">
461				<h3 id="view-binding-sources">bindingSources</h3>
462				<code>view.bindingSources</code>
463				<p class="draft">This API is a working draft. Implementation may change.</p>
464				<p>A hash table defining additional binding sources to be added to the view's binding context. Binding sources are instances of <tt>Backbone.Model</tt> and/or <tt>Backbone.Collection</tt>. By default, an Epoxy view configures two potential binding sources: the view's <b>model</b> and <b>collection</b> properties are automatically added to the binding context under the aliases <tt>$model</tt> and <tt>$collection</tt>. Additional model and collection data sources may be specified within the <b>bindingSources</b> hash; these additional data sources will be added into the binding context under the alias <tt>$sourceName</tt>.</p>
465
466				<p>Additionally, model data sources provide aliases to all of their attributes within the binding context. In the case of the default <tt>$model</tt> data source, all model attributes are aliased within the binding context using their normal <tt>attribute</tt> name. For additional model sources added through the <b>bindingSources</b> hash, model attributes are added under the alias <tt>source_attributeName</tt>. This avoids attribute naming conflicts while binding multiple models of the same type.</p>
467
468<pre>
469<code class="js">// Epoxy view specifying five data sources:
470var BindingView = Backbone.Epoxy.View.extend({
471    model: new Backbone.Model({name: "Luke Skywalker"}),
472    collection: new Backbone.Collection(),
473    bindingSources: {
474        han: new Backbone.Model({name: "Han Solo"}),
475        obiwan: new Backbone.Model({name: "Obi-Wan Kenobi"}),
476        users: new Backbone.Collection()
477    }
478});
479
480// Resulting binding context (psudocode):
481{
482    $model: &lt;Backbone.Model&gt;,
483    $collection: &lt;Backbone.Collection&gt;,
484    $han: &lt;Backbone.Model&gt;,
485    $obiwan: &lt;Backbone.Model&gt;,
486    $users: &lt;Backbone.Collection&gt;,
487    name: &lt;$model:name&gt;,
488    han_name: &lt;$han:name&gt;,
489    obiwan_name: &lt;$obiwan:name&gt;
490}
491</code>
492</pre>
493				<p>A note about Collection sources: Epoxy bindings do not register a <tt>"change"</tt> event on collection sources to avoid generally superfluous updates. Instead, you may manually trigger an <tt>"update"</tt> event on a collection source to refresh its bindings.</p>
494			</div>
495			
496			<div class="section">
497				<h3 id="view-remove">remove</h3>
498				<code>view.remove()</code>
499				<p>Override wrapper for the Backbone Views's native <b>remove</b> method. This override calls <b>removeBindings</b>, then defers to the Backbone View's native <b>remove</b> method.</p>
500			</div>
501			
502			<div class="section">
503				<h3 id="view-remove-bindings">removeBindings</h3>
504				<code>view.removeBindings()</code>
505				<p>Removes and cleans up all bindings applied to the view. All binding hooks will be nullified, leaving the view's DOM elements formatted in their final bound state. The <b>removeBindings</b> method is automatically called with the <b>remove</b> method. Be mindful that you should manually call <b>removeBindings</b> when deprecating an Epoxy view without specifically calling its <b>remove</b> method.</p>
506			</div>
507			
508			<div class="section">
509				<h2 id="binding-handlers">View Binding Handlers</h2>
510				<p>Binding handlers are used to interchange model data with elements in the view. The Epoxy <tt>View</tt> includes default binding handlers for common tasks such as managing a bound element's content, class, and style. However, don't feel limited to just Epoxy's out-of-the-box binding handlers. You may easily <a href="#view-binding-handlers">define your own binding handlers</a> within a view.</p>
511				
512				<p>One or more binding handlers may be applied to an element as a comma-separated properties list (here shown using DOM attribute bindings):</p>
513
514<pre>
515<code class="html">&lt;a data-bind="text:linkText,attr:{href:linkUrl,title:linkText}"&gt;&lt;/a&gt;</code>
516</pre>
517				<p>In the above example, <tt>"text:"</tt> and <tt>"attr:"</tt> are binding handlers, while <tt>"linkText"</tt> and <tt>"linkUrl"</tt> are the bound model attributes assigned to them. In the case of the <tt>"attr"</tt> handler, its value is a hash of attribute names, each with an associated model value.</p>
518				
519				<p>Be aware that binding declarations are parsed as JavaScript <tt>Object</tt> bodies, therefore a binding declaration <i>must</i> conform to proper JavaScript syntax. To give due credit, Epoxy's binding system is modeled after the clever technique used in <a href="http://knockoutjs.com/">Knockout.js</a>. However, Epoxy deliberately limits some of Knockout's free-form binding allowances, such as inline concatenation (which becomes overly technical within the presentation layer, IMHO). If you're coming from Knockout, don't expect to write as much inline binding JavaScript.</p>
520			</div>
521			
522			<div class="section">
523				<h3 id="handler-attr">attr</h3>
524				<span class="alias">read-only</span>
525				<code>data-bind="attr:{name:modelAttribute,'data-name':modelAttribute}"</code>
526				<p>Binds model attribute values to a list of element attributes. Attribute bindings are defined as a hash of key/value pairs, where each key defines an element attribute and the model reference defines the attribute value. Attribute keys may be defined as strings.</p>
527			</div>
528			
529			<div class="section">
530				<h3 id="handler-checked">checked</h3>
531				<span class="alias">read-write</span>
532				<code>data-bind="checked:modelAttribute"</code>
533				<p>Binds <tt>checkbox</tt> and <tt>radio</tt> elements to the model. The binding behavior differs slightly for various element/value combinations:</p>
534
535				<ul>
536					<li><b>Radios:</b> a bound <tt>radio</tt> element will become checked when the element's <tt>value</tt> matches the bound model attribute. Checking a radio will set its <tt>value</tt> to the bound model attribute.</li>
537
538					<li><b>Checkbox arrays:</b> when a <tt>checkbox</tt> element is bound to an <tt>Array</tt> model attribute, the element will be checked while its <tt>value</tt> exists within the value array, and unchecked while its <tt>value</tt> is absent from the array. Likewise, toggling the element's <tt>checked</tt> property will add and remove its value from the bound array. Keep in mind that arrays modified within a native <tt>Backbone.Model</tt> will NOT trigger a <tt>"change"</tt> event unless the array <i>instance</i> is changed. Using an <tt>Epoxy.Model</tt> observable will help here by managing object copies, and by performing array comparisons by content.</li>
539
540				 	<li><b>Checkbox toggles:</b> when a <tt>checkbox</tt> element is bound to a primitive model attribute (types <tt>String</tt>, <tt>Boolean</tt>, or <tt>Number</tt>), the element will be checked based on a loosely-typed assessment of the model attribute's truthiness. When the element's <tt>"checked"</tt> status is toggled, it will submit a <tt>Boolean</tt> value back to the model attribute.</li>
541				</ul>
542			</div>
543			
544			<div class="section">
545				<h3 id="handler-classes">classes</h3>
546				<span class="alias">read-only</span>
547				<code>data-bind="classes:{active:modelAttr,'is-active':modelAttr}"</code>
548				<p>Toggles a list of element class names based on the truthiness of their bound model attributes. Class bindings are defined as a hash of key/value pairs, where each key defines a class name and is value references a model attribute that will be loosely-type checked for truthiness; truthy attributes will enable their class, while falsey attributes will disable their class. Class name keys may be defined as strings.</p>
549			</div>
550			
551			<div class="section">
552				<h3 id="handler-collection">collection</h3>
553				<span class="alias">read-only</span>
554				<code>data-bind="collection:$collectionSource"</code>
555				<p>Manages the display of a <tt>Backbone.Collection</tt>. The bound collection must specify a <tt>Backbone.View</tt> constructor for displaying its models, at which time the <b>collection</b> handler will manage adding, removing, resorting, and resetting a list of those views to synchronize the display of the collection's contents. The <b>collection</b> binding performs discrete view management, where collection models will be assigned a single view instance for their lifespans, rather than re-rendering all collection views in response to changes. You may choose to use an <tt>Epoxy.View</tt> constructor for the display of individual collection items, allowing each collection view item to bind to its respective model.</p>
556
557				<p>The <b>collection</b> binding requires the following setup:</p>
558
559				<ul>
560					<li>The binding must target a <tt>Backbone.Collection</tt> data source available within the <b><a href="#view-binding-context">binding context</a></b>. </li>
561
562					<li>The bound collection must have a property called <b>view</b>, which defines a <tt>Backbone.View</tt> constructor for rendering collection items.</li>
563				</ul>
564
565<pre class="js"><code class="js">// View for individual collection items:
566var ListItemView = Backbone.View.extend({
567    tagName: "li",
568    initialize: function() {
569        this.$el.text( this.model.get("label") );
570    }
571});
572
573// Collection defining a Model and View:
574var ListCollection = Backbone.Collection.extend({
575    model: Backbone.Model,
576    view: ListItemView
577});
578
579// Binding view for list of collection items:
580var ListView = Backbone.Epoxy.View.extend({
581    el: "&lt;ul data-bind='collection:$collection'&gt;&lt;/ul&gt;",
582    initialize: function() {
583        this.collection = new ListCollection();
584        this.collection.reset([{label: "Luke Skywalker"}, {label: "Han Solo"}]);
585    }
586});
587
588var view = new ListView();</code></pre>
589
590				<p>Note that the <b>collection</b> binding does not register a <tt>"change"</tt> event on its collection to avoid generally superfluous updates. Instead, you may manually trigger an <tt>"update"</tt> event on the collection to refresh its bindings. For a working demonstration of the <b>collection</b> binding, see the <a href="tutorials.html#epoxy-todos">Epoxy ToDos</a> demo.</p>
591			</div>
592			
593			<div class="section">
594				<h3 id="handler-css">css</h3>
595				<span class="alias">read-only</span>
596				<code>data-bind="css:{color:modelAttribute,'font-size':modelAttribute}"</code>
597				<p>Binds a list of CSS styles to model attributes. CSS style bindings are defined as a hash of key/value pairs, where each key defines a CSS style name and the model attribute defines the style's literal value. CSS keys may be defined as strings.</p>
598			</div>
599			
600			<div class="section">
601				<h3 id="handler-disabled">disabled</h3>
602				<span class="alias">read-only</span>
603				<code>data-bind="disabled:modelAttribute"</code>
604				<p>Toggles a form element's <tt>"disabled"</tt> property based on a loosely-typed assessment of the bound model attribute's truthiness. A truthy value disables the element (inversion of the <b>enabled</b> handler).</p>
605			</div>
606			
607			<div class="section">
608				<h3 id="handler-enabled">enabled</h3>
609				<span class="alias">read-only</span>
610				<code>data-bind="enabled:modelAttribute"</code>
611				<p>Toggles a form element's <tt>"disabled"</tt> status based on a loosely-typed assessment of the bound model attribute's truthiness. A truthy value enables the element (inversion of the <b>disabled</b> handler).</p>
612			</div>
613			
614			<div class="section">
615				<h3 id="handler-events">events</h3>
616				<span class="alias">read-only</span>
617				<code>data-bind="events:['keydown','focus']"</code>
618				<p>The <b>events</b> handler is a special binding used to parameterize what DOM events will trigger changes for read-write element bindings. By default, all read-write bindings will subscribe to their bound element's <tt>"change"</tt> event to trigger model updates. You may bind additional DOM event triggers for the element by listing them in the <b>events</b> array.</p>
619			</div>
620			
621			<div class="section">
622				<h3 id="handler-html">html</h3>
623				<span class="alias">read-only</span>
624				<code>data-bind="html:modelAttribute"</code>
625				<p>Sets the element's HTML content to the bound model attribute value. Uses the jQuery <b>html</b> method.</p>
626			</div>
627			
628			<div class="section">
629				<h3 id="handler-options">options</h3>
630				<span class="alias">read-only</span>
631				<code>data-bind="options:arraySource"</code>
632				<p>Binds a <tt>&lt;select&gt;</tt> element's options to an array data source. The bound data source may be an <tt>Array</tt> object, or a <tt>Backbone.Collection</tt> instance from which the <b>models</b> array will be used. Array contents may be formatted using one of the following methods:</p>
633				
634				<ul>
635					<li><tt>["Luke", "Han", "Leia"]</tt> : Primitives list. Given an array of primitives, options will be created using the array values as both the text and value for each option.</li>
636					
637					<li><tt>[{label:"Luke", value:"1"}, {label:"Leia", value:"2"}]</tt> : Label/value pairs. Given an array of objects, options will be created using each object's <b>label</b> and <b>value</b> properties as the text and value of each option.</li>
638					
639					<li><tt>Backbone.Collection</tt> : Models list. The collection's <b>models</b> array will be used as the array source. Options will be created using each model's <b>label</b> and <b>value</b> attributes as the text and value of each option. An <tt>Epoxy.Model</tt> may be used to virtualize these values as observable/computed attributes if needed. Note that the <b>options</b> binding does not register a <tt>"change"</tt> event on its collection to avoid generally superfluous updates. Instead, you may manually trigger an <tt>"update"</tt> event on the collection to refresh its bindings.</li>
640				</ul>
641				
642<pre><code class="js">observableDefaults: {
643    list1: ["Luke"],
644    list2: [{label:"Luke", value:"0"}],
645    list3: new Backbone.Collection( {models:[{label:"Luke", value:"0"}]} )
646}
647
648// list1: &lt;option&nbsp;value='Luke'&gt;Luke&lt;/option&gt;
649// list2: &lt;option&nbsp;value='0'&gt;Luke&lt;/option&gt;
650// list3: &lt;option&nbsp;value='0'&gt;Luke&lt;/option&gt;
651</code></pre>
652				
653				<p>To manage a <tt>&lt;select&gt;</tt> element's default first option and/or empty state, you may choose to also include the <b>optionsDefault</b> and/or <b>optionsEmpty</b> helper bindings.</p>
654			</div>
655			
656			<div class="section">
657				<h3 id="handler-options-default">optionsDefault</h3>
658				<span class="alias">read-only</span>
659				<code>data-bind="options:opts,optionsDefault:modelAttribute"</code>
660				<p>Defines a default option made available at the top of a <tt>&lt;select&gt;</tt> element in addition to the <b>options</b> list. This binding must be used in tandem with the <b>options</b> binding. The <b>optionsDefault</b> value will appear as the first and/or only item in the select, regardless if the <b>options</b> list has content. The <b>optionsDefault</b> value may be formatted using one of the following methods:</p>
661				
662				<ul>
663					<li><tt>"Default Value"</tt> : Given a primitive value (string, number, or boolean), the default option will be created using the primitive as both text and value of the option.</li>
664					
665					<li><tt>{label:"Default", value:""}</tt> : Given an object, the default option will be created using the object's <b>label</b> and <b>value</b> properties as the text and value of the option.</li>
666					
667					<li><tt>Backbone.Model</tt> : Given a Backbone Model, the default option will be created using the model's <b>label</b> and <b>value</b> attributes as the text and value of the option. An <tt>Epoxy.Model</tt> may be used to virtualize these as observable/computed attributes if needed.</li>
668				</ul>
669				
670<pre><code class="js">observableDefaults: {
671    default1: "Choose...",
672    default2: {label:"Choose...", value:""},
673    default3: new Backbone.Model({label:"Choose...", value:""})
674}
675
676// default1: &lt;option&nbsp;value='Choose...'&gt;Choose...&lt;/option&gt;
677// default2: &lt;option&nbsp;value=''&gt;Choose...&lt;/option&gt;
678// default3: &lt;option&nbsp;value=''&gt;Choose...&lt;/option&gt;
679</code></pre>
680				<p>You may also choose to declare <b>optionsDefault</b> as a static object within a binding declaration, as in:<br><tt>data-bind="value:val,options:opts,optionsDefault:{label:'Choose...', value:''}"</tt></p>
681			</div>
682			
683			<div class="section">
684				<h3 id="handler-options-empty">optionsEmpty</h3>
685				<span class="alias">read-only</span>
686				<code>data-bind="options:opts,optionsEmpty:modelAttribute"</code>
687				<p>Defines a placeholder option to apply to an empty <tt>&lt;select&gt;</tt> element, and automatically disables the select element while displaying this placeholder. This must be used in tandem with the <b>options</b> binding, and is generally only needed when there is no default option. The empty placeholder option may be formatted using one of the following methods:</p>
688				
689				<ul>
690					<li><tt>"Placeholder Value"</tt> : Given a primitive value (string, number, or boolean), the placeholder option will be created using the primitive as both text and value of the option.</li>
691					
692					<li><tt>{label:"None", value:""}</tt> : Given an object, the placeholder option will be created using the object's <b>label</b> and <b>value</b> properties as the text and value of the option.</li>
693					
694					<li><tt>Backbone.Model</tt> : Given a Backbone Model, the placeholder option will be created using the model's <b>label</b> and <b>value</b> attributes as the text and value of the option. An <tt>Epoxy.Model</tt> may be used to virtualize these as observable/computed attributes if needed.</li>
695				</ul>
696				
697<pre><code class="js">observableDefaults: {
698    empty1: "None",
699    empty2: {label:"None", value:""},
700    empty3: new Backbone.Model({label:"None", value:""})
701}
702
703// empty1: &lt;option&nbsp;value='None'&gt;None&lt;/option&gt;
704// empty2: &lt;option&nbsp;value=''&gt;None&lt;/option&gt;
705// empty3: &lt;option&nbsp;value=''&gt;None&lt;/option&gt;
706</code></pre>
707				
708				<p>You may also choose to declare <b>optionsEmpty</b> as a static object within a binding declaration, as in:<br><tt>data-bind="value:val,options:opts,optionsEmpty:{label:'none', value:''}"</tt></p>
709			</div>
710			
711			<div class="section">
712				<h3 id="handler-text">text</h3>
713				<span class="alias">read-only</span>
714				<code>data-bind="text:modelAttribute"</code>
715				<p>Sets the element's text content to the bound model attribute value. Uses the jQuery <b>text</b> method.</p>
716			</div>
717			
718			<div class="section">
719				<h3 id="handler-toggle">toggle</h3>
720				<span class="alias">read-only</span>
721				<code>data-bind="toggle:modelAttribute"</code>
722				<p>Toggles the element's display based on a loosely-typed assessment of the bound model attribute's truthiness. Uses the jQuery <b>toggle( [boolean] )</b> method.</p>
723			</div>
724			
725			<div class="section">
726				<h3 id="handler-value">value</h3>
727				<span class="alias">read-write</span>
728				<code>data-bind="value:modelAttribute"</code>
729				<p>Binds an input element's (<tt>input</tt>, <tt>select</tt>, <tt>textarea</tt>) value to an underlying model attribute. The element will set its <tt>value</tt> to the bound model attribute upon change event triggers (see the <b><a href="#handler-events">events</a></b> handler), and update its <tt>value</tt> when the underlying model attribute changes.</p>
730			</div>
731			
732			<div class="section">
733				<h2 id="binding-operators">View Binding Operators</h2>
734				<p>Binding operators provide a layer of flexibility for formatting data attributes directly within a binding declaration; they allow values to be formatted for binding-specific implementations:</p>
735
736<pre><code class="html">&lt;span data-bind="toggle:not(firstName)"&gt;Please enter a …

Large files files are truncated, but you can click here to view the full file