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 |