PageRenderTime 78ms CodeModel.GetById 32ms 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. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <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.">
  8. <meta name="author" content="Greg MacWilliam">
  9. <meta name="viewport" content="width=device-width, initial-scale=1">
  10. <meta name="apple-mobile-web-app-title" content="Epoxy.js">
  11. <meta name="application-name" content="Epoxy.js">
  12. <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
  13. <link rel="icon" href="favicon.ico" type="image/x-icon">
  14. <link href="style/reset.css" rel="stylesheet">
  15. <link href="style/screen.css" rel="stylesheet">
  16. <script type="text/javascript">
  17. var _gaq = _gaq || [];
  18. _gaq.push(['_setAccount', 'UA-39215101-1']);
  19. _gaq.push(['_trackPageview']);
  20. (function() {
  21. var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  22. ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  23. var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  24. })();
  25. </script>
  26. </head>
  27. <body>
  28. <div id="page">
  29. <div class="banner clearfix" role="banner">
  30. <p class="title"><span><b>Epoxy</b>.js</span> Elegant Data Binding for Backbone</p>
  31. <div class="download">
  32. <a href="js/backbone.epoxy.min.js" class="download-button">Download Epoxy 0.10.0</a>
  33. <p class="download-info">8k min, 2k gzip <i>|</i> <a href="https://github.com/gmac/backbone.epoxy">GitHub Full Source</a></p>
  34. </div>
  35. </div>
  36. <div class="navigation" role="navigation">
  37. <ul class="nav-main clearfix">
  38. <li><a href="index.html">About Epoxy.js</a></li>
  39. <li><a href="tutorials.html">Getting Started</a></li>
  40. <li class="active"><a href="documentation.html">Documentation</a></li>
  41. </ul>
  42. <div class="nav-toc">
  43. <div class="nav-toc-content">
  44. <b><a href="#model">Epoxy.Model</a></b>
  45. <ul>
  46. <li><b><a href="#model-extend">extend</a></b></li>
  47. <li><b><a href="#model-constructor">constructor</a></b></li>
  48. <li><a href="#model-add-computed">addComputed</a></li>
  49. <li><a href="#model-add-observable">addObservable</a></li>
  50. <li><a href="#model-clear-observables">clearObservables</a></li>
  51. <li><a href="#model-computeds">computeds</a></li>
  52. <li><a href="#model-destroy">destroy</a></li>
  53. <li><a href="#model-get">get</a></li>
  54. <li><a href="#model-get-copy">getCopy</a></li>
  55. <li><a href="#model-has-observable">hasObservable</a></li>
  56. <li><a href="#model-modify-array">modifyArray</a></li>
  57. <li><a href="#model-modify-object">modifyObject</a></li>
  58. <li><a href="#model-observable-defaults">observableDefaults</a></li>
  59. <li><a href="#model-remove-observable">removeObservable</a></li>
  60. <li><a href="#model-set">set</a></li>
  61. </ul>
  62. <b><a href="#view">Epoxy.View</a></b>
  63. <ul>
  64. <li><b><a href="#view-extend">extend</a></b></li>
  65. <li><b><a href="#view-constructor">constructor</a></b></li>
  66. <li><b><a href="#view-binding-context">binding context</a></b></li>
  67. <li><a href="#view-apply-bindings">applyBindings</a></li>
  68. <li><a href="#view-binding-handlers">bindingHandlers</a></li>
  69. <li><a href="#view-bindings">bindings</a></li>
  70. <li><a href="#view-binding-sources">bindingSources</a></li>
  71. <li><a href="#view-remove">remove</a></li>
  72. <li><a href="#view-remove-bindings">removeBindings</a></li>
  73. </ul>
  74. <b><a href="#binding-handlers">View Binding Handlers</a></b>
  75. <ul>
  76. <li><a href="#handler-attr">attr</a></li>
  77. <li><a href="#handler-checked">checked</a></li>
  78. <li><a href="#handler-classes">classes</a></li>
  79. <li><a href="#handler-collection">collection</a></li>
  80. <li><a href="#handler-css">css</a></li>
  81. <li><a href="#handler-disabled">disabled</a></li>
  82. <li><a href="#handler-enabled">enabled</a></li>
  83. <li><a href="#handler-events">events</a></li>
  84. <li><a href="#handler-html">html</a></li>
  85. <li><a href="#handler-options">options</a></li>
  86. <li><a href="#handler-options-default">optionsDefault</a></li>
  87. <li><a href="#handler-options-empty">optionsEmpty</a></li>
  88. <li><a href="#handler-text">text</a></li>
  89. <li><a href="#handler-toggle">toggle</a></li>
  90. <li><a href="#handler-value">value</a></li>
  91. </ul>
  92. <b><a href="#binding-operators">View Binding Operators</a></b>
  93. <ul>
  94. <li><a href="#operator-all">all</a></li>
  95. <li><a href="#operator-any">any</a></li>
  96. <li><a href="#operator-format">format</a></li>
  97. <li><a href="#operator-length">length</a></li>
  98. <li><a href="#operator-none">none</a></li>
  99. <li><a href="#operator-not">not</a></li>
  100. <li><a href="#operator-select">select</a></li>
  101. </ul>
  102. </div>
  103. </div>
  104. </div>
  105. <div class="main" role="main">
  106. <h1>Documentation</h1>
  107. <div class="section">
  108. <h2 id="model">Epoxy.Model</h2>
  109. <p>The Epoxy Model object extends <tt>Backbone.Model</tt>, providing a new model abstract to be extended into your application.</p>
  110. <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>
  111. <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>
  112. </div>
  113. <div class="section">
  114. <h3 id="model-extend">extend</h3>
  115. <code>Backbone.Epoxy.Model.extend(properties, [classProperties])</code>
  116. <p>Extends the <tt>Epoxy.Model</tt> constructor for use in your own implementation.</p>
  117. </div>
  118. <div class="section">
  119. <h3 id="model-constructor">constructor</h3>
  120. <code>new Backbone.Epoxy.Model([attributes], [options])</code>
  121. <p>Creates a new <tt>Epoxy.Model</tt> instance.</p>
  122. </div>
  123. <div class="section">
  124. <h3 id="model-add-observable">addObservable</h3>
  125. <code>model.addObservable(name, value)</code>
  126. <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>
  127. <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>
  128. <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>
  129. <pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model();
  130. model.addObservable("isSelected", false);
  131. alert( model.get("isSelected") );</code>
  132. </pre>
  133. <p>Use the <b><a href="#model-observable-defaults">observableDefaults</a></b> hash to automatically construct observables on your model instances.</p>
  134. </div>
  135. <div class="section">
  136. <h3 id="model-add-computed">addComputed</h3><br>
  137. <code>model.addComputed(name, params) or...</code><br>
  138. <code>model.addComputed(name, getter, [setter], [*deps])</code>
  139. <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>
  140. <p id="model-computed-params">The <b>addComputed</b> method is called with an attribute name and a params object defining the following:</p>
  141. <ul>
  142. <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>
  143. <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>
  144. <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>
  145. </ul>
  146. <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>
  147. <pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({price:100});
  148. model.addComputed("formattedPrice", {
  149. deps: ["price"],
  150. get: function() {
  151. return "$"+ this.get("price");
  152. },
  153. set: function( value ) {
  154. return {price: parseInt(value.replace("$", ""))}
  155. }
  156. });
  157. alert( model.get("formattedPrice") ); // '$100'
  158. model.set("formattedPrice", "$150");
  159. alert( model.get("price") ); // 150</code>
  160. </pre>
  161. <p><b id="model-computed-deps">Automatic Dependency Mapping</b></p>
  162. <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>
  163. <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>
  164. <ul>
  165. <li>All model references (the parent model, or others) are instances of <tt>Epoxy.Model</tt>.</li>
  166. <li>All model attributes are accessed using their model's <b>get</b> method.</li>
  167. <li>All <b>get</b> calls are free of conditional logic (keep reading...)</li>
  168. </ul>
  169. <p>Regarding conditional <b>get</b> calls: this situation may create unreachable getters that cannot be automatically mapped. Consider the following BROKEN example:</p>
  170. <pre>
  171. <code class="js">var model = new Backbone.Epoxy.Model({
  172. shortName: "Luke",
  173. fullName: "Luke Skywalker",
  174. active: false
  175. });
  176. // BROKEN:
  177. model.addComputed("displayName", function() {
  178. return this.get("active") ? this.get("fullName") : this.get("shortName");
  179. });</code>
  180. </pre>
  181. <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>
  182. <pre>
  183. <code class="js">// FIXED:
  184. model.addComputed("displayName", function() {
  185. var fullName = this.get("fullName");
  186. var shortName = this.get("shortName");
  187. return this.get("active") ? fullName : shortName;
  188. });</code>
  189. </pre>
  190. <p>Use the <b><a href="#model-computeds">computeds</a></b> hash to automatically construct computed observables on your model instances.</p>
  191. </div>
  192. <div class="section">
  193. <h3 id="model-clear-observables">clearObservables</h3>
  194. <code>model.clearObservables()</code>
  195. <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>
  196. </div>
  197. <div class="section">
  198. <h3 id="model-computeds">computeds</h3>
  199. <code>model.computeds</code>
  200. <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>
  201. <pre>
  202. <code class="js">var ComputedModel = Backbone.Epoxy.Model.extend({
  203. defaults: {
  204. firstName: "Luke",
  205. lastName: "Skywalker"
  206. },
  207. computeds: {
  208. fullNameParams: {
  209. deps: ["firstName", "lastName"],
  210. get: function() {
  211. return this.get("firstName") +" "+ this.get("lastName");
  212. },
  213. set: function( value ) {
  214. var first = value.split(" ")[0];
  215. var last = value.split(" ")[1];
  216. return {firstName: first, lastName: last};
  217. }
  218. },
  219. fullNameGetter: function() {
  220. return this.get("firstName") +" "+ this.get("lastName");
  221. }
  222. }
  223. });</code>
  224. </pre>
  225. </div>
  226. <div class="section">
  227. <h3 id="model-destroy">destroy</h3>
  228. <code>model.destroy([options])</code>
  229. <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>
  230. </div>
  231. <div class="section">
  232. <h3 id="model-get">get</h3>
  233. <code>model.get(attribute)</code>
  234. <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>
  235. <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>
  236. </div>
  237. <div class="section">
  238. <h3 id="model-get-copy">getCopy</h3>
  239. <code>model.getCopy(attribute)</code>
  240. <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>
  241. </div>
  242. <div class="section">
  243. <h3 id="model-has-observable">hasObservable</h3>
  244. <code>model.hasObservable(attribute)</code>
  245. <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>
  246. </div>
  247. <div class="section">
  248. <h3 id="model-modify-array">modifyArray</h3>
  249. <code>model.modifyArray(attribute, arrayMethod, [*args])</code>
  250. <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>
  251. <pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({wordList:[]});
  252. model.modifyArray("wordList", "push", "deathstar");
  253. alert( model.get("wordList").length );</code>
  254. </pre>
  255. </div>
  256. <div class="section">
  257. <h3 id="model-modify-object">modifyObject</h3>
  258. <code>model.modifyObject(attribute, objectProperty, value)</code>
  259. <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>
  260. <pre><button class="run">Run</button><code class="js">var model = new Backbone.Epoxy.Model({ wordsDict:{} });
  261. model.modifyObject("wordsDict", "deathstar", true);
  262. alert( model.get("wordsDict").hasOwnProperty("deathstar") );</code>
  263. </pre>
  264. </div>
  265. <div class="section">
  266. <h3 id="model-observable-defaults">observableDefaults</h3>
  267. <code>model.observableDefaults</code>
  268. <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>
  269. <pre>
  270. <code class="js">var ComputedModel = Backbone.Epoxy.Model.extend({
  271. observableDefaults: {
  272. isSelected: false,
  273. keysList: function() { return ["a", "b"]; }
  274. }
  275. });</code>
  276. </pre>
  277. </div>
  278. <div class="section">
  279. <h3 id="model-remove-observable">removeObservable</h3>
  280. <code>model.removeObservable(attribute)</code>
  281. <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>
  282. </div>
  283. <div class="section">
  284. <h3 id="model-set">set</h3>
  285. <code>model.set(attributes, [options])</code>
  286. <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>
  287. <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>
  288. </div>
  289. <div class="section">
  290. <h2 id="view">Epoxy.View</h2>
  291. <p>The Epoxy View object extends <tt>Backbone.View</tt>, providing a new view abstract to be extended into your application.</p>
  292. <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>
  293. <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>
  294. </div>
  295. <div class="section">
  296. <h3 id="view-extend">extend</h3>
  297. <code>Backbone.Epoxy.View.extend(properties, [classProperties])</code>
  298. <p>Extends the <tt>Epoxy.View</tt> constructor for use in your own implementation.</p>
  299. </div>
  300. <div class="section">
  301. <h3 id="view-constructor">constructor</h3>
  302. <code>new Backbone.Epoxy.View([options])</code>
  303. <p>Creates a new <tt>Epoxy.View</tt> instance.</p>
  304. </div>
  305. <div class="section">
  306. <h3 id="view-binding-context">binding context</h3>
  307. <code>{$model:model, $collection:collection, [*attributes]}</code>
  308. <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>
  309. <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>
  310. </div>
  311. <div class="section">
  312. <h3 id="view-apply-bindings">applyBindings</h3>
  313. <code>view.applyBindings()</code>
  314. <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>
  315. <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>
  316. <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>
  317. </div>
  318. <div class="section">
  319. <h3 id="view-binding-handlers">bindingHandlers</h3>
  320. <code>view.bindingHandlers</code>
  321. <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>
  322. <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>
  323. <pre>
  324. <code class="js">var BindingView = Backbone.Epoxy.View.extend({
  325. bindingHandlers: {
  326. printList: {
  327. set: function( $element, value ) {
  328. $element.text( value.join(",") );
  329. },
  330. get: function( $element, value ) {
  331. return $element.text().split(",");
  332. }
  333. }
  334. }
  335. });</code>
  336. </pre>
  337. <ul>
  338. <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>
  339. <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>
  340. </ul>
  341. <!--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-->
  342. <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>
  343. <pre>
  344. <code class="js">var BindingView = Backbone.Epoxy.View.extend({
  345. bindingHandlers: {
  346. printList: function( $element, value ) {
  347. $element.text( value.join(",") );
  348. }
  349. }
  350. });</code>
  351. </pre>
  352. </div>
  353. <div class="section">
  354. <h3 id="view-bindings">bindings</h3>
  355. <code>view.bindings</code>
  356. <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>
  357. <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>
  358. <pre>
  359. <code class="js">var BindingModel = Backbone.Model.extend({
  360. defaults: {
  361. firstName: "Luke",
  362. lastName: "Skywalker"
  363. }
  364. });
  365. var BindingView = Backbone.Epoxy.View.extend({
  366. model: new BindingModel(),
  367. bindings: {
  368. "input.first-name": "value:firstName,events:['keyup']",
  369. "input.last-name": "value:lastName,events:['keyup']"
  370. }
  371. });</code>
  372. </pre>
  373. <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>
  374. <pre>
  375. <code class="js">var BindingModel = Backbone.Model.extend({
  376. defaults: {
  377. firstName: "Luke",
  378. lastName: "Skywalker"
  379. }
  380. });
  381. var BindingView = Backbone.Epoxy.View.extend({
  382. el: "#binding-view"
  383. model: new BindingModel(),
  384. bindings: "data-bind"
  385. });
  386. &lt;div id="binding-view"&gt;
  387. &lt;p&gt;First: &lt;input type="text" data-bind="value:firstName,events:['keyup']"&gt;&lt;/p&gt;
  388. &lt;p&gt;Last: &lt;input type="text" data-bind="value:lastName,events:['keyup']"&gt;&lt;/p&gt;
  389. &lt;/div&gt;</code>
  390. </pre>
  391. </div>
  392. <div class="section">
  393. <h3 id="view-binding-sources">bindingSources</h3>
  394. <code>view.bindingSources</code>
  395. <p class="draft">This API is a working draft. Implementation may change.</p>
  396. <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>
  397. <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>
  398. <pre>
  399. <code class="js">// Epoxy view specifying five data sources:
  400. var BindingView = Backbone.Epoxy.View.extend({
  401. model: new Backbone.Model({name: "Luke Skywalker"}),
  402. collection: new Backbone.Collection(),
  403. bindingSources: {
  404. han: new Backbone.Model({name: "Han Solo"}),
  405. obiwan: new Backbone.Model({name: "Obi-Wan Kenobi"}),
  406. users: new Backbone.Collection()
  407. }
  408. });
  409. // Resulting binding context (psudocode):
  410. {
  411. $model: &lt;Backbone.Model&gt;,
  412. $collection: &lt;Backbone.Collection&gt;,
  413. $han: &lt;Backbone.Model&gt;,
  414. $obiwan: &lt;Backbone.Model&gt;,
  415. $users: &lt;Backbone.Collection&gt;,
  416. name: &lt;$model:name&gt;,
  417. han_name: &lt;$han:name&gt;,
  418. obiwan_name: &lt;$obiwan:name&gt;
  419. }
  420. </code>
  421. </pre>
  422. <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>
  423. </div>
  424. <div class="section">
  425. <h3 id="view-remove">remove</h3>
  426. <code>view.remove()</code>
  427. <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>
  428. </div>
  429. <div class="section">
  430. <h3 id="view-remove-bindings">removeBindings</h3>
  431. <code>view.removeBindings()</code>
  432. <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>
  433. </div>
  434. <div class="section">
  435. <h2 id="binding-handlers">View Binding Handlers</h2>
  436. <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>
  437. <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>
  438. <pre>
  439. <code class="html">&lt;a data-bind="text:linkText,attr:{href:linkUrl,title:linkText}"&gt;&lt;/a&gt;</code>
  440. </pre>
  441. <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>
  442. <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>
  443. </div>
  444. <div class="section">
  445. <h3 id="handler-attr">attr</h3>
  446. <span class="alias">read-only</span>
  447. <code>data-bind="attr:{name:modelAttribute,'data-name':modelAttribute}"</code>
  448. <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>
  449. </div>
  450. <div class="section">
  451. <h3 id="handler-checked">checked</h3>
  452. <span class="alias">read-write</span>
  453. <code>data-bind="checked:modelAttribute"</code>
  454. <p>Binds <tt>checkbox</tt> and <tt>radio</tt> elements to the model. The binding behavior differs slightly for various element/value combinations:</p>
  455. <ul>
  456. <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>
  457. <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>
  458. <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>
  459. </ul>
  460. </div>
  461. <div class="section">
  462. <h3 id="handler-classes">classes</h3>
  463. <span class="alias">read-only</span>
  464. <code>data-bind="classes:{active:modelAttr,'is-active':modelAttr}"</code>
  465. <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>
  466. </div>
  467. <div class="section">
  468. <h3 id="handler-collection">collection</h3>
  469. <span class="alias">read-only</span>
  470. <code>data-bind="collection:$collectionSource"</code>
  471. <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>
  472. <p>The <b>collection</b> binding requires the following setup:</p>
  473. <ul>
  474. <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>
  475. <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>
  476. </ul>
  477. <pre class="js"><code class="js">// View for individual collection items:
  478. var ListItemView = Backbone.View.extend({
  479. tagName: "li",
  480. initialize: function() {
  481. this.$el.text( this.model.get("label") );
  482. }
  483. });
  484. // Collection defining a Model and View:
  485. var ListCollection = Backbone.Collection.extend({
  486. model: Backbone.Model,
  487. view: ListItemView
  488. });
  489. // Binding view for list of collection items:
  490. var ListView = Backbone.Epoxy.View.extend({
  491. el: "&lt;ul data-bind='collection:$collection'&gt;&lt;/ul&gt;",
  492. initialize: function() {
  493. this.collection = new ListCollection();
  494. this.collection.reset([{label: "Luke Skywalker"}, {label: "Han Solo"}]);
  495. }
  496. });
  497. var view = new ListView();</code></pre>
  498. <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>
  499. </div>
  500. <div class="section">
  501. <h3 id="handler-css">css</h3>
  502. <span class="alias">read-only</span>
  503. <code>data-bind="css:{color:modelAttribute,'font-size':modelAttribute}"</code>
  504. <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>
  505. </div>
  506. <div class="section">
  507. <h3 id="handler-disabled">disabled</h3>
  508. <span class="alias">read-only</span>
  509. <code>data-bind="disabled:modelAttribute"</code>
  510. <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>
  511. </div>
  512. <div class="section">
  513. <h3 id="handler-enabled">enabled</h3>
  514. <span class="alias">read-only</span>
  515. <code>data-bind="enabled:modelAttribute"</code>
  516. <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>
  517. </div>
  518. <div class="section">
  519. <h3 id="handler-events">events</h3>
  520. <span class="alias">read-only</span>
  521. <code>data-bind="events:['keydown','focus']"</code>
  522. <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>
  523. </div>
  524. <div class="section">
  525. <h3 id="handler-html">html</h3>
  526. <span class="alias">read-only</span>
  527. <code>data-bind="html:modelAttribute"</code>
  528. <p>Sets the element's HTML content to the bound model attribute value. Uses the jQuery <b>html</b> method.</p>
  529. </div>
  530. <div class="section">
  531. <h3 id="handler-options">options</h3>
  532. <span class="alias">read-only</span>
  533. <code>data-bind="options:arraySource"</code>
  534. <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>
  535. <ul>
  536. <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>
  537. <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>
  538. <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>
  539. </ul>
  540. <pre><code class="js">observableDefaults: {
  541. list1: ["Luke"],
  542. list2: [{label:"Luke", value:"0"}],
  543. list3: new Backbone.Collection( {models:[{label:"Luke", value:"0"}]} )
  544. }
  545. // list1: &lt;option&nbsp;value='Luke'&gt;Luke&lt;/option&gt;
  546. // list2: &lt;option&nbsp;value='0'&gt;Luke&lt;/option&gt;
  547. // list3: &lt;option&nbsp;value='0'&gt;Luke&lt;/option&gt;
  548. </code></pre>
  549. <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>
  550. </div>
  551. <div class="section">
  552. <h3 id="handler-options-default">optionsDefault</h3>
  553. <span class="alias">read-only</span>
  554. <code>data-bind="options:opts,optionsDefault:modelAttribute"</code>
  555. <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>
  556. <ul>
  557. <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>
  558. <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>
  559. <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>
  560. </ul>
  561. <pre><code class="js">observableDefaults: {
  562. default1: "Choose...",
  563. default2: {label:"Choose...", value:""},
  564. default3: new Backbone.Model({label:"Choose...", value:""})
  565. }
  566. // default1: &lt;option&nbsp;value='Choose...'&gt;Choose...&lt;/option&gt;
  567. // default2: &lt;option&nbsp;value=''&gt;Choose...&lt;/option&gt;
  568. // default3: &lt;option&nbsp;value=''&gt;Choose...&lt;/option&gt;
  569. </code></pre>
  570. <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>
  571. </div>
  572. <div class="section">
  573. <h3 id="handler-options-empty">optionsEmpty</h3>
  574. <span class="alias">read-only</span>
  575. <code>data-bind="options:opts,optionsEmpty:modelAttribute"</code>
  576. <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>
  577. <ul>
  578. <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>
  579. <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>
  580. <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>
  581. </ul>
  582. <pre><code class="js">observableDefaults: {
  583. empty1: "None",
  584. empty2: {label:"None", value:""},
  585. empty3: new Backbone.Model({label:"None", value:""})
  586. }
  587. // empty1: &lt;option&nbsp;value='None'&gt;None&lt;/option&gt;
  588. // empty2: &lt;option&nbsp;value=''&gt;None&lt;/option&gt;
  589. // empty3: &lt;option&nbsp;value=''&gt;None&lt;/option&gt;
  590. </code></pre>
  591. <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>
  592. </div>
  593. <div class="section">
  594. <h3 id="handler-text">text</h3>
  595. <span class="alias">read-only</span>
  596. <code>data-bind="text:modelAttribute"</code>
  597. <p>Sets the element's text content to the bound model attribute value. Uses the jQuery <b>text</b> method.</p>
  598. </div>
  599. <div class="section">
  600. <h3 id="handler-toggle">toggle</h3>
  601. <span class="alias">read-only</span>
  602. <code>data-bind="toggle:modelAttribute"</code>
  603. <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>
  604. </div>
  605. <div class="section">
  606. <h3 id="handler-value">value</h3>
  607. <span class="alias">read-write</span>
  608. <code>data-bind="value:modelAttribute"</code>
  609. <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>
  610. </div>
  611. <div class="section">
  612. <h2 id="binding-operators">View Binding Operators</h2>
  613. <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>
  614. <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