| OLD | NEW |
| (Empty) |
| 1 polymer_expressions | |
| 2 =================== | |
| 3 | |
| 4 | |
| 5 Polymer expressions are an expressive syntax that can be used in HTML templates | |
| 6 with Dart. | |
| 7 | |
| 8 Templates are one feature of Polymer.dart, which is a set of comprehensive UI | |
| 9 and utility components for building web applications. | |
| 10 This package is automatically included with the | |
| 11 [Polymer](https://pub.dartlang.org/packages/polymer) package | |
| 12 because Polymer expressions are the default expression syntax | |
| 13 in Polymer Dart apps. | |
| 14 The [Polymer.dart homepage][home_page] | |
| 15 contains a list of features, project status, | |
| 16 installation instructions, tips for upgrading from Web UI, | |
| 17 and links to other documentation. | |
| 18 | |
| 19 | |
| 20 ## Overview | |
| 21 | |
| 22 Polymer expressions allow you to write complex binding expressions, with | |
| 23 property access, function invocation, list/map indexing, and two-way filtering | |
| 24 like: | |
| 25 | |
| 26 ```html | |
| 27 {{ person.title + " " + person.getFullName() | upppercase }} | |
| 28 ``` | |
| 29 | |
| 30 ### Model-Driven Views (MDV) | |
| 31 [MDV][mdv] allows you to define templates directly in HTML that are rendered by | |
| 32 the browser into the DOM. Templates are bound to a data model, and changes to | |
| 33 the data are automatically reflected in the DOM, and changes in HTML inputs are | |
| 34 assigned back into the model. The template and model are bound together via | |
| 35 binding expressions that are evaluated against the model. These binding | |
| 36 expressions are placed in double-curly-braces, or "mustaches". | |
| 37 | |
| 38 Example: | |
| 39 | |
| 40 ```html | |
| 41 <template> | |
| 42 <p>Hello {{ person.name }}</p> | |
| 43 </template> | |
| 44 ``` | |
| 45 | |
| 46 MDV includes a very basic binding syntax which only allows a series of | |
| 47 dot-separate property names. | |
| 48 | |
| 49 [mdv]: http://www.polymer-project.org/platform/mdv.html | |
| 50 | |
| 51 ### Custom binding syntaxes with binding delegate | |
| 52 | |
| 53 While MDV's built-in syntax is very basic, it does allow custom syntaxes called | |
| 54 "binding delegates" to be installed and used. A binding delegate can interpret | |
| 55 the contents of mustaches however it likes. PolymerExpressions is such a | |
| 56 binding delegate. | |
| 57 | |
| 58 Example: | |
| 59 | |
| 60 ```html | |
| 61 <template bind> | |
| 62 <p>Hello {{ person.title + " " + person.getFullName() | uppercase }}</p> | |
| 63 </template> | |
| 64 ``` | |
| 65 | |
| 66 ## Usage | |
| 67 | |
| 68 ### Installing from Pub | |
| 69 | |
| 70 Add the following to your pubspec.yaml file: | |
| 71 | |
| 72 ```yaml | |
| 73 dependencies: | |
| 74 polymer_expressions: any | |
| 75 ``` | |
| 76 | |
| 77 Hint: check https://pub.dartlang.org/packages/polymer_expressions for the latest | |
| 78 version number. | |
| 79 | |
| 80 Then import polymer_expressions.dart: | |
| 81 | |
| 82 import 'package:polymer_expressions/polymer_expressions.dart'; | |
| 83 | |
| 84 ### Registering a binding delegate | |
| 85 | |
| 86 **Polymer Expressions are now the default syntax for `<polymer-element>` custom | |
| 87 elements.** | |
| 88 | |
| 89 You do not need to manually register the bindingDelegate if your bindings are | |
| 90 inside a custom element. However, if you want to use polymer_expressions outside | |
| 91 a custom element, read on: | |
| 92 | |
| 93 Binding delegates must be installed on a template before they can be used. | |
| 94 For example, set the bindingDelegate property of your template | |
| 95 elements to an instance of PolymerExpressions. The templates will then use the | |
| 96 PolymerExpressions instance to interpret | |
| 97 binding expressions. | |
| 98 | |
| 99 ```dart | |
| 100 import 'dart:html'; | |
| 101 import 'package:polymer_expressions/polymer_expressions.dart'; | |
| 102 | |
| 103 main() { | |
| 104 var template = query('#my_template'); | |
| 105 template.bindingDelegate = new PolymerExpressions(); | |
| 106 } | |
| 107 ``` | |
| 108 | |
| 109 ### Registering top-level variables | |
| 110 | |
| 111 Before a top-level variable can be used, it must be registered. The | |
| 112 PolymerExpressions constructor takes a map of named values to use as variables. | |
| 113 | |
| 114 ```dart | |
| 115 main() { | |
| 116 var globals = { | |
| 117 'uppercase': (String v) => v.toUpperCase(), | |
| 118 'app_id': 'my_app_123', | |
| 119 }; | |
| 120 var template = query('#my_template'); | |
| 121 template.bindingDelegate = new PolymerExpressions(globals: globals); | |
| 122 } | |
| 123 ``` | |
| 124 | |
| 125 ## Features | |
| 126 | |
| 127 ### The model and scope | |
| 128 | |
| 129 Polymer Expressions allow binding to more than just the model assigned to a | |
| 130 template instance. Top-level variables can be defined so that you can use | |
| 131 filters, global variables and constants, functions, etc. These variables and the | |
| 132 model are held together in a container called a Scope. Scopes can be nested, | |
| 133 which happens when template tags are nested. | |
| 134 | |
| 135 ### Two-way bindings | |
| 136 | |
| 137 Bindings can be used to modify the data model based on events in the DOM. The | |
| 138 most common case is to bind an <input> element's value field to a model | |
| 139 property and have the property update when the input changes. For this to work, | |
| 140 the binding expression must be "assignable". Only a subset of expressions are | |
| 141 assignable. Assignable expressions cannot contain function calls, operators, and | |
| 142 any index operator must have a literal argument. Assignable expressions can | |
| 143 contain filter operators as long as all the filters are two-way transformers. | |
| 144 | |
| 145 Some restrictions may be relaxed further as allowed. | |
| 146 | |
| 147 Assignable Expressions: | |
| 148 | |
| 149 * `foo` | |
| 150 * `foo.bar` | |
| 151 * `items[0].description` | |
| 152 * `people['john'].name` | |
| 153 * `product.cost | convertCurrency('ZWD')` where `convertCurrency` evaluates to | |
| 154 a Tranformer object. | |
| 155 | |
| 156 Non-Assignable Expressions: | |
| 157 | |
| 158 * `a + 1` | |
| 159 * `!c` | |
| 160 * `foo()` | |
| 161 * `person.lastName | uppercase` where `uppercase` is a filter function. | |
| 162 | |
| 163 ### Null-Safety | |
| 164 | |
| 165 Expressions are generally null-safe. If an intermediate expression yields `null` | |
| 166 the entire expression will return null, rather than throwing an exception. | |
| 167 Property access, method invocation and operators are null-safe. Passing null to | |
| 168 a function that doesn't handle null will not be null safe. | |
| 169 | |
| 170 ### Streams | |
| 171 | |
| 172 Polymer Expressions have experimental support for binding to streams, and when | |
| 173 new values are passed to the stream, the template updates. The feature is not | |
| 174 fully implemented yet. | |
| 175 | |
| 176 See the examples in /example/streams for more details. | |
| 177 | |
| 178 ## Syntax | |
| 179 | |
| 180 ### Property access | |
| 181 | |
| 182 Properties on the model and in the scope are looked up via simple property | |
| 183 names, like `foo`. Property names are looked up first in the top-level | |
| 184 variables, next in the model, then recursively in parent scopes. Properties on | |
| 185 objects can be access with dot notation like `foo.bar`. | |
| 186 | |
| 187 The keyword `this` always refers to the model if there is one, otherwise `this` | |
| 188 is `null`. If you have model properties and top-level variables with the same | |
| 189 name, you can use `this` to refer to the model property. | |
| 190 | |
| 191 ### Literals | |
| 192 | |
| 193 Polymer Expressions support number, boolean, string, and map literals. Strings | |
| 194 can use either single or double quotes. | |
| 195 | |
| 196 * Numbers: `1`, `1.0` | |
| 197 * Booleans: `true`, `false` | |
| 198 * Strings: `'abc'`, `"xyz"` | |
| 199 * Maps: `{ 'a': 1, 'b': 2 }` | |
| 200 | |
| 201 List literals are planned, see [issue 9](https://github.com/dart-lang/polymer_ex
pressions/issues/9) | |
| 202 | |
| 203 ### Functions and methods | |
| 204 | |
| 205 If a property is a function in the scope, a method on the model, or a method on | |
| 206 an object, it can be invoked with standard function syntax. Functions and | |
| 207 Methods can take arguments. Named arguments are not supported. Arguments can be | |
| 208 literals or variables. | |
| 209 | |
| 210 Examples: | |
| 211 | |
| 212 * Top-level function: `myFunction()` | |
| 213 * Top-level function with arguments: `myFunction(a, b, 42)` | |
| 214 * Model method: `aMethod()` | |
| 215 * Method on nested-property: `a.b.anotherMethod()` | |
| 216 | |
| 217 ### Operators | |
| 218 | |
| 219 Polymer Expressions supports the following binary and unary operators: | |
| 220 | |
| 221 * Arithmetic operators: +, -, *, /, %, unary + and - | |
| 222 * Comparison operators: ==, !=, <=, <, >, >= | |
| 223 * Boolean operators: &&, ||, unary ! | |
| 224 | |
| 225 Expressions do not support bitwise operators such as &, |, << and >>, or increme
nt/decrement operators (++ and --) | |
| 226 | |
| 227 ### List and Map indexing | |
| 228 | |
| 229 List and Map like objects can be accessed via the index operator: [] | |
| 230 | |
| 231 Examples: | |
| 232 | |
| 233 * `items[2]` | |
| 234 * `people['john']` | |
| 235 | |
| 236 Unlike JavaScript, list and map contents are not generally available via | |
| 237 property access. That is, the previous examples are not equivalent to `items.2` | |
| 238 and `people.john`. This ensures that access to properties and methods on Lists | |
| 239 and Maps is preserved. | |
| 240 | |
| 241 ### Filters and transformers | |
| 242 | |
| 243 A filter is a function that transforms a value into another, used via the pipe | |
| 244 syntax: `value | filter` Any function that takes exactly one argument can be | |
| 245 used as a filter. | |
| 246 | |
| 247 Example: | |
| 248 | |
| 249 If `person.name` is "John", and a top-level function named `uppercase` has been | |
| 250 registered, then `person.name | uppercase` will have the value "JOHN". | |
| 251 | |
| 252 The pipe syntax is used rather than a regular function call so that we can | |
| 253 support two-way bindings through transformers. A transformer is a filter that | |
| 254 has an inverse function. Transformers must extend or implement the `Transformer` | |
| 255 class, which has `forward()` and `reverse()` methods. | |
| 256 | |
| 257 ### Repeating templates | |
| 258 | |
| 259 A template can be repeated by using the "repeat" attribute with a binding. The | |
| 260 binding can either evaluate to an Iterable, in which case the template is | |
| 261 instantiated for each item in the iterable and the model of the instance is | |
| 262 set to the item, or the binding can be a "in" iterator expression, in which | |
| 263 case a new variable is added to each scope. | |
| 264 | |
| 265 The following examples produce the same output. | |
| 266 | |
| 267 Evaluate to an iterable: | |
| 268 | |
| 269 ```html | |
| 270 <template repeat="{{ items }}"> | |
| 271 <div>{{ }}</div> | |
| 272 </template> | |
| 273 ``` | |
| 274 | |
| 275 "in" expression: | |
| 276 | |
| 277 ```html | |
| 278 <template repeat="{{ item in items }}"> | |
| 279 <div>{{ item }}</div> | |
| 280 </template> | |
| 281 ``` | |
| 282 | |
| 283 ## Status | |
| 284 | |
| 285 The syntax implemented is experimental and subject to change, in fact, it | |
| 286 **will** change soon. The goal is to be compatible with Polymer's binding | |
| 287 syntax. We will announce breaking changes on the | |
| 288 [web-ui@dartlang.org mailing list][web-ui-list]. | |
| 289 | |
| 290 Please [file issues on Dart project page](http://dartbug.com/new) | |
| 291 for any bugs you find or for feature requests. Make a note that it applies to | |
| 292 "package:polymer_expressions" | |
| 293 | |
| 294 You can discuss Polymer Expressions on the | |
| 295 [web-ui@dartlang.org mailing list][web-ui-list]. | |
| 296 | |
| 297 [web-ui-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/web-ui | |
| OLD | NEW |