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 |