Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/site/articles/dart-web-components/index.markdown

Issue 11066080: Initial version of Dart web components article (Closed) Base URL: git@github.com:sigmundch/dartlang.org.git@master
Patch Set: roudn1 of comments Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/site/_plugins/code_sample.rb ('k') | src/site/css/style.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 ---
2 layout: default
3 title: "Dart Web Components"
4 rel:
5 author: siggi-cherem
6 description: "A brief introduction to Dart web components."
7 has-permalinks: true
8 ---
9
10 # {{ page.title }}
11 _Written by Siggi Cherem<br />
12 October 2012 <br />
13 Updated: October 2012_
14
15 {% comment %}
16
17 README --- General notes about editing this file:
18
19 * This file is processed by liquid, which evaluates {{ var }} and removes the
20 \{\{ and \}\} symbols from the code. Because we use \{\{\}\} in our template
21 expressions, we need to escape them in a special way. Unfortunately using
22 \{\{\}\} within code makes the backslash show up. There are 2 ways to work
23 around this:
24 * Doing {{'{{'}}: lyquid evaluates it as a string expression returning \{\{.
25 * Using \{\% raw \%\} blocks.
26
27 * the codesample blocks are an extension added to jekyll written as 'liquid'
28 blocks. The meaning of a block like this:
29 \{\% codesample 80 \%\}
30
31 text
32 \{\% sample 10 20 url \%\}
33 \{\% endcodesample \%\}
34 is that we'll create a table, the first colum will have sample source code (in
35 this case "text"). This code can have a \{\% highlight \%\} section, but other
36 than that, no markdown is supported here :(. The column width is specified as
37 the first argument of the codesample tag above it (in this example 80 means
38 80%). The \{\% sample \%\} tag defines the width, height, and url for an iframe
39 that will contain the runnining version of the code sample.
40
41 {% endcomment %}
42
43 Dart web components provide a templating, data binding, and encapsulation, to
44 help you write web applications at scale. An early version is available in the
45 [dart-web-components project][dwc].
46
47 Many UI frameworks exist for writing web apps in
48 JavaScript -- for example [backbone], [ember.js][ember], and [angularjs][angular ].
49 Recently, the web community has been pushing to include some of the common ideas
50 of these frameworks directly into the browser platform. A result has
51 been added features like shadow DOM and [web components][wc], and other
52 experimental and cool ideas like [model-driven views][mdv] (MDV).
53
54 Dart web components combine the ideas of web components and MDV, adapting them
55 to work well with Dart. Dart web components take advantage of advanced browser
56 features when possible, emulating missing features when necessary.
57
58 In this article, we'll walk through some examples that illustrate how to write
59 and use Dart web components. Soon we'll be creating a document with a detailed
60 specification (link TBR), and another document with instructions on how to use
61 the Dart web component tools (link TBR).
62
63 ## MDV templates in Dart
64
65 Most UI frameworks provide some form of templating to declare views with a
66 succinct declarative syntax. Dart web components closely follow the MDV syntax,
67 which is basically HTML with small extensions to enable the following features:
68
69 * **One-way data binding**: Embed data into your UI
70 * **Two-way data binding**: Keep data in sync with UI changes
71 * **Events listeners**: Easily attach code that reacts to UI events
72 * **Conditionals**: Selectively show parts of the UI
73 * **Loops**: Construct lists and tables by iterating over collections
74
75 We made some changes to make sure that using Dart with MDV feels natural, but
76 otherwise all the concepts from MDV are available here. Let's take a look at
77 examples for each of these features.
78
79 ### One-way data bindings
80
81 You can inject data in your template using `{{'{{'}}expression}}`. The
82 example below shows a simple hello world program where the value of the dart
Jennifer Messerly 2012/10/10 01:18:29 uppercase Dart?
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
83 top-level variable `dataValue` is injected in the page automatically. The right
84 column shows the app generated from this code running in an iframe.
85
86 {% codesample 90 %}
87 {% highlight html %}
88 {% raw %}
89 <html><body>
90 <div>Hello {{dataValue}}!</div>
91 <script type="application/dart">
92 String dataValue;
93 main() {
94 var today = new Date.now();
95 dataValue = 'world ${today.year}-${today.month}-${today.day}';
96 }
97 </script>
98 </body></html>
99 {% endraw %}
100 {% endhighlight %}
101 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/helloworld.html.html %}
Jennifer Messerly 2012/10/10 01:18:29 meta: include links to the sample code in source c
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 cool. done.
102 {% endcodesample %}
103
104 The template expression we just saw above is what we call a **one-way data
105 binding**. Like in many other UI libraries and frameworks, we automatically
106 watch for changes in your data and ensure the UI is up-to-date whenever the data
107 changes.
108
109 Dart web components do this by using the `watchers.dart` library (included with
Jennifer Messerly 2012/10/10 01:18:29 Should this link to the apidoc for watchers? (I re
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 good point. I made it a link to the source code fo
110 the dart web components package). You can listen for changes and notify everyone
111 when changes might occur. The following example illustrates how you would
112 manually use this library:
113
114 {% codesample 90 %}
115 {% highlight html %}
116 {% raw %}
117 <html><body>
118 <div>Hello counter: {{count}}</div>
119 <script type="application/dart">
120 import 'dart:html';
121 import 'package:web_components/watcher.dart' as watchers;
122 int count;
123 main() {
124 count = 0;
125 window.setInterval(() {
126 count++;
127 watchers.dispatch();
128 }, 1000);
129 }
130 </script>
131 </body></html>
132 {% endraw %}
133 {% endhighlight %}
134 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/counter.html.html %}
135 {% endcodesample %}
136
137 The code manually invokes `watchers.dispatch()` to make a change visible to the
Jennifer Messerly 2012/10/10 01:18:29 likewise would be cool to link to API docs
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 cool idea.
138 UI. Every now and then it is useful to access watchers directly, but we have
139 found that we often don't have to manually write these calls. In particular,
140 Dart web components will automatically make the dispatch call when using
141 common features like two-way binding and attaching event listeners.
142
143 ### Two-way data bindings
144
145 Two-way data bindings lets us define that we want a DOM element's value
146 (typically an input box or a check box) to be kept in sync with the value of a
147 Dart variable. The following example creates a two way binding between `str` and
148 `input.value`. We declare this binding by writing the attribute
149 `data-bind="value:str"`.
150
151 {% codesample 90 %}
152 {% highlight html %}
153 {% raw %}
154 <html><body>
155 <div>
156 Input:
157 <input type="text" data-bind="value:str" placeholder="type something here">
158 <div> Value: {{str}}</div>
159 <div> Length: {{str.length}}</div>
160 </div>
161 <script type="application/dart">
162 String str = '';
163 main() {}
164 </script>
165 </body></html>
166 {% endraw %}
167 {% endhighlight %}
168 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/twoway.html.html %}
169 {% endcodesample %}
170
171 This is a simple example where Dart web components automatically dispatch
172 events for data-model changes. In particular, whenever you update the value of
173 the text box, the string and it's length will be updated in other parts of the
174 UI.
175
176 ### Data-binding expressions
177
178 We want to make Dart web components have, to a great extend, feature and design
Jennifer Messerly 2012/10/10 01:18:29 typo: "extent" instead of "extend"
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 :), thx
179 parity with MDV. For this reason, we try to match the same syntax of their
180 template language where it is appropriate. MDV restricts data-binding
Jennifer Messerly 2012/10/10 01:18:29 remove "where it is appropriate"
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
181 expressions to an expression language containing variables, field dereferences,
182 and array accesses. This means that expressions in MDV templates would likely be
183 valid Dart and valid JavaScript as well. That also means that advanced Dart expr essions
Jennifer Messerly 2012/10/10 01:18:29 not sure we are trying to stay under 80 col? this
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 thx, done.
184 are not valid between `{{'{{'}}expressions}}`, however you can always hide
185 complex expressions under a getter in Dart and use the getter property within
186 the template.
187
188 A full specification of the expression syntax will be available soon in our
189 [specification document (link TBR)][].
Jennifer Messerly 2012/10/10 01:18:29 This renders showing the link. Did you mean to do
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
190
191 ### Conditionals
192
193 Template conditionals allow you to selectively activate parts of the UI. We
194 write a conditional by wrapping a portion of the UI in a `<template>` tag and
195 writing the condition in an attribute of the form `instantiate="if expr"`. For
196 instance, the following example only shows `They match!` when both input boxes
197 have the same text:
198
199 {% codesample 90 %}
200 {% highlight html %}
201 {% raw %}
202 <html><body>
203 <div>
204 <div> Input1: <input type="text" data-bind="value:str1"></div>
205 <div> Input2: <input type="text" data-bind="value:str2"></div>
206 <template instantiate="if str1 == str2">
207 <div>They match!</div>
208 </template>
209 </div>
210 <script type="application/dart">
211 String str1 = '';
212 String str2 = '';
213 main() {}
214 </script>
215 </body></html>
216 {% endraw %}
217 {% endhighlight %}
218 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/matchstrings.html.html %}
219 {% endcodesample %}
220
221 ### Loops
222
223 Template loops allow us to iterate over iterable Dart collections. The following
224 example shows a fun little app that has search as you type. We use the two-way
225 data binding to store the `query` string, then we compute a filtered set of
226 results and display it using a looping construct.
227
228 {% codesample 90 %}
229 {% highlight html %}
230 {% raw %}
231 <html><body>
232 <div>
233 <span>Search for something:</span>
234 <input type="text" data-bind="value:query">
235 <div>
236 <template instantiate='if noMatches'><span>No matches</span></template>
237 <template instantiate='if !noMatches'><span>Top results:</span></template>
238 </div>
239 <div><ul>
240 <template iterate='fruit in results'>
241 <li>{{fruit}}</li>
242 </template>
243 </ul></div>
244 </div>
245 <script type="application/dart">
246 String query = '';
247 List<String> values = const [ 'Apple', 'Apricot', 'Avocado', 'Banana',
248 'Blackberry', 'Blackcurrant', 'Blueberry', 'Currant', 'Cherry',
249 'Clementine', 'Date', 'Durian', 'Fig', 'Gooseberry', 'Grape',
250 'Grapefruit', 'Guava', 'Huckleberry', 'Kiwi', 'Lemon', 'Lime',
251 'Lychee', 'Mandarine', 'Mango', 'Cantaloupe', 'Honeydew melon',
252 'Nectarine', 'Orange', 'Peach', 'Pear', 'Plum', 'Pineapple',
253 'Pomegranate', 'Raspberry', 'Redcurrant', 'Star fruit', 'Strawberry',
254 'Tangerine', 'Tomato', 'Watermelon'];
255
256 List<String> get results {
257 var res = values.filter(
258 (v) => v.toLowerCase().contains(query.toLowerCase()));
259 if (res.length > 20) {
260 res.length = 20;
261 res.add('... and many more');
262 }
263 return res;
264 }
265
266 bool get noMatches => results.isEmpty();
267
268 main() {}
269 </script>
270 </body></html>
271 {% endraw %}
272 {% endhighlight %}
273 {% sample 300px 600px http://dart-lang.github.com/dart-web-components/example/ex plainer/fruitsearch.html.html %}
274 {% endcodesample %}
275
276
277 ### Listen to UI events
278
279 Templates also gives us a succinct way to listen for arbitrary UI events and
280 associate those events with Dart code. We do this by using `data-action`
281 attributes. Here is an example that listens for click events:
282
283 {% codesample 90 %}
284 {% highlight html %}
285 {% raw %}
286 <html><body>
287 <div>
288 <button data-action="click:increment">Click me</button>
289 <span>(click count: {{count}})</span>
290 </div>
291 <script type="application/dart">
292 int count = 0;
293 void increment(e) { count++; }
294 main() {}
295 </script>
296 </body></html>
297 {% endraw %}
298 {% endhighlight %}
299 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/clickcount.html.html %}
300 {% endcodesample %}
301
302
303 ### Templating summary
304
305 Templates solve one part of the problem in building web applications: reducing
306 the amount of boilerplate code that is used to set up a typical
307 model-view-viewmodel architecture. One-way databindings, two-way databindings,
Jennifer Messerly 2012/10/10 01:18:29 "databinding" with a space? "data binding"
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
308 and data-action listeners, help reduce the need for manually creating controller
309 objects that do these bindings by hand. If we combine bindings, conditionals,
310 and loops, we have a formula to create simple and sophisticated views in a
311 declarative fashion.
312
313 However, templating alone is not enough. We need mechanisms to encapsulate and
314 abstract views so we can scale to build larger web apps. This is were we need
315 web components.
316
317 ## Web components in Dart
318
319 Web components provide a way to create encapsulated reusable views, which will
320 be useful to build medium and large applications. A web component basically
321 includes a view, some data, and behavior. In our case, views are described in
322 terms of templates, while data and behavior are written directly in Dart.
323
324 ### Declaring a component
325
326 Web components are declared using a special `<element>` tag. For example, we can
327 take the click-count example above and make it a component as follows:
328
329 {% highlight html %}
330 {% raw %}
331 <html><body>
332 <element name="x-counter" constructor="CounterComponent" extends="div">
333 <template>
334 <div>
335 <button data-action="click:increment">Click me</button>
336 <span>(click count: {{count}})</span>
337 </div>
338 </template>
339 <script type="application/dart">
340 import 'package:web_components/web_component.dart';
341
342 class CounterComponent extends WebComponent {
343 int count = 0;
344 void increment(e) { count++; }
345 }
346 </script>
347 </element>
348 <!-- more below... -->
349 </body></html>
350 {% endraw %}
351 {% endhighlight %}
352
353 The `<element>` tag basically declares a component whose view is defined
Jennifer Messerly 2012/10/10 01:18:29 perhaps remove "basically"? "visual appearance" mi
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
354 under the child `<template>` tag, and whose behavior code is embedded or sourced
355 by the child `<script>` tag.
356
357 Components can be thought as if they are extending DOM nodes, their declaration
Jennifer Messerly 2012/10/10 01:18:29 "HTML elements" instead of "DOM nodes"?
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
358 indicates which DOM node they extend from using the `extends` attribute. The
359 attribute `constructor="CounterComponent"` indicates that this component's
360 behavior is defined in the `CounterComponent` class. Today, this class must
361 extend from `WebComponent`, but in the future it will be possible to extend
362 directly from the DOM Node that we declared in the `extends` attribute. For
363 instance, `class CounterComponent extends DivElement ...`.
364
365 The `<element>` tag also declares the component's name with the `name`
366 attribute. This name will be used to instantiate this component later on.
367
368 ### Instantiating a component
369
370 Instantiating a component can be done in two ways: using its name as a tag, e.g.
371 `<x-counter></x-counter>` or using setting the `is` attribute on the
372 tag that the component extends from. For example,
373
374 {% codesample 90 %}
375 {% highlight html %}
376 {% raw %}
377 <html><body>
378 <!-- ... element declared as above -->
379 <div is="x-counter"></div>
380 <script type="application/dart">
381 main(){}
382 </script>
383 </body></html>
384 {% endraw %}
385 {% endhighlight %}
386 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent.html.html %}
387 {% endcodesample %}
388
389
390 ### Passing data to a component
391
392 All of the public fields in a component declaration can be initialized directly
393 when we instantiate a component. We can do this by writing a special
394 `data-value` attribute in the HTML. For instance, the following example
395 instantiates two click-counter components (declared just like above), but
396 initializes the `count` field of the component to a different value each time.
397
398 {% codesample 90 %}
399 {% highlight html %}
400 {% raw %}
401 <html><body>
402 <!-- ... element declared as above -->
403 <div is="x-counter" data-value="count: myNumber"></div>
404 <div is="x-counter" data-value="count: 5"></div>
405 <script type="application/dart">
406 int myNumber = 12;
407 main(){}
408 </script>
409 </body></html>
410 {% endraw %}
411 {% endhighlight %}
412 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent5.html.html %}
413 {% endcodesample %}
414
415 ### Working at scale
416
417 When developing larger web applications, it is really useful to be able to split
418 the work and divide pieces of your application in multiple files. It is also
419 useful to create reusable components that you embed in several places of your
420 application or even across several applications.
421
422 Web components allows us to do import other components using `<link
Jennifer Messerly 2012/10/10 01:18:29 typo: "to import" instead of "to do import"
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
423 rel="components">` tags. For example, suppose we created a file
424 `clickcounter.html` that contains the declaration of the click-counter component
Jennifer Messerly 2012/10/10 01:18:29 wondering if we should name the component "x-click
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
425 as we had above. Then, our last example could be rewritten as follows:
426
427 {% highlight html %}
428 {% raw %}
429 <html>
430 <head>
431 <link rel="components" href="clickcounter.html">
432 </head>
433 <body>
434 <div is="x-counter" data-value="count: myNumber"></div>
435 <div is="x-counter" data-value="count: 5"></div>
436 <script type="application/dart">
437 int myNumber = 12;
438 main(){}
439 </script>
440 </body>
441 </html>
442 {% endraw %}
443 {% endhighlight %}
444
445 ### Upcoming features
446
447 We are still adding features and making changes to Dart web components. Here are
448 some of the features we are working on:
449
450 * Support for sub-components. Using a special `<content>` tag, a component
451 can embed nodes that will be provided when instantiating it. For instance,
452 you could write a component that puts a frame around an image as follows:
453
454 {% highlight html %}
455 {% raw %}
456 <html>
457 <body>
458 <element name="x-myframe">
459 <template>
460 <!-- some complex wrapping happens here ... -->
461 <div class="framestyle">...<content></content>...</div>
462 </template>
463 </element>
464
465 <div is="x-myframe">
466 <!-- img will be included where we wrote <content> above -->
467 <img src="...">
468 </div>
469 </body>
470 </html>
471 {% endraw %}
472 {% endhighlight %}
473
474 * Alternative MDV conditional and listing constructs. Instead of using a
475 `<template>` tags, you will be able to use `instantiate` and
476 `iterate` attributes directly on any element. This is important because in
477 some parts of the HTML is not valid to write `<template>` tags. For example,
478 this feature will make it possible to iterate on table rows and cells.
479
480 ## Developing and using Dart web components
481
482 We are making several tools available to make it easy to create and deploy
483 projects that use dart web components. We have a compiler tool that can be run
484 offline to generate efficient code for your components. The generated code will
485 try to use the native features available in browsers, but otherwise it will
486 resort to other techniques to ensure that the semantics of dart web components
487 are the same everywhere.
488
489 We have added integration with the Dart editor, so that changes to source files
490 can be compiled automatically in the background. We are also developing an
491 extension for dartium that will be able to compile components on the fly as
492 you load them. Both the editor and dartium integration will provide you with a
493 smooth edit/refresh cycle.
494
495 More details about our tools will be available soon [(link TBR)][].
496
497 ## Exploring more
498
499 There are many resources to explore and learn more about Dart web components.
500 Check out our Dartisans episode on this topic:
501
502 <iframe width="560" height="315" src="http://www.youtube.com/embed/zUdQkSwslzc" frameborder="0" allowfullscreen></iframe>
503
504 You can also follow the project in [github][dwc], track and file bugs in our
Jennifer Messerly 2012/10/10 01:18:29 think this should be "GitHub" to match how they wr
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
505 [issue tracker][bugs], and play with other examples in our repo, like our port
506 of [todomvc][todomvcindwc].
Jennifer Messerly 2012/10/10 01:18:29 likewise, I think this should be "TodoMVC" to matc
Siggi Cherem (dart-lang) 2012/10/10 01:50:41 Done.
507
508 If you have any questions, feel free to send us email directly at
509 [misc@dartlang.org](mailto:misc@dartlang.org).
510
511
512 [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html
513 [mdv]: http://code.google.com/p/mdv/
514 [dwc]: https://github.com/dart-lang/dart-web-components/
515 [bugs]: https://github.com/dart-lang/dart-web-components/issues
516 [backbone]: http://backbonejs.org/
517 [angular]: http://angularjs.org/
518 [ember]: http://emberjs.com/
519 [todomvcindwc]: https://github.com/dart-lang/dart-web-components/tree/master/exa mple/todomvc
OLDNEW
« no previous file with comments | « src/site/_plugins/code_sample.rb ('k') | src/site/css/style.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698