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: 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
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 JavaScript -- for example
48 [backbone], [ember.js][ember], and [angularjs][angular]. Recently, the web
49 community has been pushing to include some of the common ideas of these
50 frameworks directly into the browser platform. A result has been added features
51 like shadow DOM and [web components][wc], and other experimental and cool ideas
Jennifer Messerly 2012/10/10 02:37:20 Still need the shadow DOM link :) http://dvcs.w3.
Siggi Cherem (dart-lang) 2012/10/10 17:20:55 Done. Thanks for the link :) I was initially going
52 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, and another document with instructions on how to use the Dart web
61 component tools.
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
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 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/helloworld.html %}
102 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/helloworld.html.html %}
103 {% endcodesample %}
104
105 The template expression we just saw above is what we call a **one-way data
106 binding**. Like in many other UI libraries and frameworks, we automatically
107 watch for changes in your data and ensure the UI is up-to-date whenever the data
108 changes.
109
110 Dart web components do this by using the [watcher.dart][watcher] library
111 (included with the Dart web components package). You can listen for changes and
112 notify everyone when changes might occur. The following example illustrates how
113 you would manually use this library:
114
115 {% codesample 90 %}
116 {% highlight html %}
117 {% raw %}
118 <html><body>
119 <div>Hello counter: {{count}}</div>
120 <script type="application/dart">
121 import 'dart:html';
122 import 'package:web_components/watcher.dart' as watchers;
123 int count;
124 main() {
125 count = 0;
126 window.setInterval(() {
127 count++;
128 watchers.dispatch();
129 }, 1000);
130 }
131 </script>
132 </body></html>
133 {% endraw %}
134 {% endhighlight %}
135 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/counter.html %}
136 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/counter.html.html %}
137 {% endcodesample %}
138
139 The code manually invokes [watchers.dispatch()][watcher.dispatch] to make a
140 change visible to the UI. Every now and then it is useful to access watchers
141 directly, but we have found that we often don't have to manually write these
142 calls. In particular, Dart web components will automatically make the dispatch
143 call when using common features like two-way binding and attaching event
144 listeners.
145
146 ### Two-way data bindings
147
148 Two-way data bindings lets us define that we want a DOM element's value
149 (typically an input box or a check box) to be kept in sync with the value of a
150 Dart variable. The following example creates a two way binding between `str` and
151 `input.value`. We declare this binding by writing the attribute
152 `data-bind="value:str"`.
153
154 {% codesample 90 %}
155 {% highlight html %}
156 {% raw %}
157 <html><body>
158 <div>
159 Input:
160 <input type="text" data-bind="value:str" placeholder="type something here">
161 <div> Value: {{str}}</div>
162 <div> Length: {{str.length}}</div>
163 </div>
164 <script type="application/dart">
165 String str = '';
166 main() {}
167 </script>
168 </body></html>
169 {% endraw %}
170 {% endhighlight %}
171 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/twoway.html %}
172 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/twoway.html.html %}
173 {% endcodesample %}
174
175 This is a simple example where Dart web components automatically dispatch
176 events for data-model changes. In particular, whenever you update the value of
177 the text box, the string and it's length will be updated in other parts of the
178 UI.
179
180 ### Data-binding expressions
181
182 We want to make Dart web components have, to a great extent, feature and design
183 parity with MDV. For this reason, we try to match the same syntax of their
184 template language. MDV restricts data-binding expressions to an expression
185 language containing variables, field dereferences, and array accesses. This
186 means that expressions in MDV templates would likely be valid Dart and valid
187 JavaScript as well. That also means that advanced Dart expressions are not valid
188 between `{{'{{'}}expressions}}`, however you can always hide complex expressions
189 under a getter in Dart and use the getter property within the template.
190
191 A full specification of the expression syntax will be available soon.
192
193 ### Conditionals
194
195 Template conditionals allow you to selectively activate parts of the UI. We
196 write a conditional by wrapping a portion of the UI in a `<template>` tag and
197 writing the condition in an attribute of the form `instantiate="if expr"`. For
198 instance, the following example only shows `They match!` when both input boxes
199 have the same text:
200
201 {% codesample 90 %}
202 {% highlight html %}
203 {% raw %}
204 <html><body>
205 <div>
206 <div> Input1: <input type="text" data-bind="value:str1"></div>
207 <div> Input2: <input type="text" data-bind="value:str2"></div>
208 <template instantiate="if str1 == str2">
209 <div>They match!</div>
210 </template>
211 </div>
212 <script type="application/dart">
213 String str1 = '';
214 String str2 = '';
215 main() {}
216 </script>
217 </body></html>
218 {% endraw %}
219 {% endhighlight %}
220 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/matchstrings.html %}
221 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/matchstrings.html.html %}
222 {% endcodesample %}
223
224 ### Loops
225
226 Template loops allow us to iterate over iterable Dart collections. The following
227 example shows a fun little app that has search as you type. We use the two-way
228 data binding to store the `query` string, then we compute a filtered set of
229 results and display it using a looping construct.
230
231 {% codesample 90 %}
232 {% highlight html %}
233 {% raw %}
234 <html><body>
235 <div>
236 <span>Search for something:</span>
237 <input type="text" data-bind="value:query">
238 <div>
239 <template instantiate='if noMatches'><span>No matches</span></template>
240 <template instantiate='if !noMatches'><span>Top results:</span></template>
241 </div>
242 <div><ul>
243 <template iterate='fruit in results'>
244 <li>{{fruit}}</li>
245 </template>
246 </ul></div>
247 </div>
248 <script type="application/dart">
249 String query = '';
250 List<String> values = const [ 'Apple', 'Apricot', 'Avocado', 'Banana',
251 'Blackberry', 'Blackcurrant', 'Blueberry', 'Currant', 'Cherry',
252 'Clementine', 'Date', 'Durian', 'Fig', 'Gooseberry', 'Grape',
253 'Grapefruit', 'Guava', 'Huckleberry', 'Kiwi', 'Lemon', 'Lime',
254 'Lychee', 'Mandarine', 'Mango', 'Cantaloupe', 'Honeydew melon',
255 'Nectarine', 'Orange', 'Peach', 'Pear', 'Plum', 'Pineapple',
256 'Pomegranate', 'Raspberry', 'Redcurrant', 'Star fruit', 'Strawberry',
257 'Tangerine', 'Tomato', 'Watermelon'];
258
259 List<String> get results {
260 var res = values.filter(
261 (v) => v.toLowerCase().contains(query.toLowerCase()));
262 if (res.length > 20) {
263 res.length = 20;
264 res.add('... and many more');
265 }
266 return res;
267 }
268
269 bool get noMatches => results.isEmpty();
270
271 main() {}
272 </script>
273 </body></html>
274 {% endraw %}
275 {% endhighlight %}
276 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/fruitsearch.html %}
277 {% sample 300px 600px http://dart-lang.github.com/dart-web-components/example/ex plainer/fruitsearch.html.html %}
278 {% endcodesample %}
279
280
281 ### Listen to UI events
282
283 Templates also gives us a succinct way to listen for arbitrary UI events and
284 associate those events with Dart code. We do this by using `data-action`
285 attributes. Here is an example that listens for click events:
286
287 {% codesample 90 %}
288 {% highlight html %}
289 {% raw %}
290 <html><body>
291 <div>
292 <button data-action="click:increment">Click me</button>
293 <span>(click count: {{count}})</span>
294 </div>
295 <script type="application/dart">
296 int count = 0;
297 void increment(e) { count++; }
298 main() {}
299 </script>
300 </body></html>
301 {% endraw %}
302 {% endhighlight %}
303 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/clickcount.html %}
304 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/clickcount.html.html %}
305 {% endcodesample %}
306
307
308 ### Templating summary
309
310 Templates solve one part of the problem in building web applications: reducing
311 the amount of boilerplate code that is used to set up a typical
312 model-view-viewmodel architecture. One-way data bindings, two-way data bindings,
313 and data-action listeners, help reduce the need for manually creating controller
314 objects that do these bindings by hand. If we combine bindings, conditionals,
315 and loops, we have a formula to create simple and sophisticated views in a
316 declarative fashion.
317
318 However, templating alone is not enough. We need mechanisms to encapsulate and
319 abstract views so we can scale to build larger web apps. This is were we need
320 web components.
321
322 ## Web components in Dart
323
324 Web components provide a way to create encapsulated reusable views, which will
325 be useful to build medium and large applications. A web component basically
326 includes a view, some data, and behavior. In our case, views are described in
327 terms of templates, while data and behavior are written directly in Dart.
328
329 ### Declaring a component
330
331 Web components are declared using a special `<element>` tag. For example, we can
332 take the click-count example above and make it a component as follows:
333
334 {% highlight html %}
335 {% raw %}
336 <html><body>
337 <element name="x-click-counter" constructor="CounterComponent" extends="div">
338 <template>
339 <div>
340 <button data-action="click:increment">Click me</button>
341 <span>(click count: {{count}})</span>
342 </div>
343 </template>
344 <script type="application/dart">
345 import 'package:web_components/web_component.dart';
346
347 class CounterComponent extends WebComponent {
348 int count = 0;
349 void increment(e) { count++; }
350 }
351 </script>
352 </element>
353 <!-- more below... -->
354 </body></html>
355 {% endraw %}
356 {% endhighlight %}
357
358 The `<element>` tag defines a component whose visual apperance is declared under
359 the child `<template>` tag, and whose behavior code is embedded or sourced by
360 the child `<script>` tag.
361
362 Components can be thought as if they are extending HTML elements, their
363 declaration indicates which element they extend from using the `extends`
364 attribute. The attribute `constructor="CounterComponent"` indicates that this
365 component's behavior is defined in the `CounterComponent` class. Today, this
366 class must extend from `WebComponent`, but in the future it will be possible to
367 extend directly from the HTML element that we declared in the `extends`
368 attribute. For instance, `class CounterComponent extends DivElement ...`.
369
370 The `<element>` tag also declares the component's name with the `name`
371 attribute. This name will be used to instantiate this component later on.
372
373 ### Instantiating a component
374
375 Instantiating a component can be done in two ways: using its name as a tag, e.g.
376 `<x-click-counter></x-click-counter>` or using setting the `is` attribute on the
377 tag that the component extends from. For example,
378
379 {% codesample 90 %}
380 {% highlight html %}
381 {% raw %}
382 <html><body>
383 <!-- ... element declared as above -->
384 <div is="x-click-counter"></div>
385 <script type="application/dart">
386 main(){}
387 </script>
388 </body></html>
389 {% endraw %}
390 {% endhighlight %}
391 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/countcomponent.html %}
392 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent.html.html %}
393 {% endcodesample %}
394
395
396 ### Passing data to a component
397
398 All of the public fields in a component declaration can be initialized directly
399 when we instantiate a component. We can do this by writing a special
400 `data-value` attribute in the HTML. For instance, the following example
401 instantiates two click-counter components (declared just like above), but
402 initializes the `count` field of the component to a different value each time.
403
404 {% codesample 90 %}
405 {% highlight html %}
406 {% raw %}
407 <html><body>
408 <!-- ... element declared as above -->
409 <div is="x-click-counter" data-value="count: myNumber"></div>
410 <div is="x-click-counter" data-value="count: 5"></div>
411 <script type="application/dart">
412 int myNumber = 12;
413 main(){}
414 </script>
415 </body></html>
416 {% endraw %}
417 {% endhighlight %}
418 {% url https://github.com/dart-lang/dart-web-components/blob/master/example/expl ainer/countcomponent5.html %}
419 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent5.html.html %}
420 {% endcodesample %}
421
422 ### Working at scale
423
424 When developing larger web applications, it is really useful to be able to split
425 the work and divide pieces of your application in multiple files. It is also
426 useful to create reusable components that you embed in several places of your
427 application or even across several applications.
428
429 Web components allows us to import other components using `<link
430 rel="components">` tags. For example, suppose we created a file
431 `clickcounter.html` that contains the declaration of the click-counter component
432 as we had above. Then, our last example could be rewritten as follows:
433
434 {% highlight html %}
435 {% raw %}
436 <html>
437 <head>
438 <link rel="components" href="clickcounter.html">
439 </head>
440 <body>
441 <div is="x-click-counter" data-value="count: myNumber"></div>
442 <div is="x-click-counter" data-value="count: 5"></div>
443 <script type="application/dart">
444 int myNumber = 12;
445 main(){}
446 </script>
447 </body>
448 </html>
449 {% endraw %}
450 {% endhighlight %}
451
452 ### Upcoming features
453
454 We are still adding features and making changes to Dart web components. Here are
455 some of the features we are working on:
456
457 * Support for sub-components. Using a special `<content>` tag, a component
458 can embed nodes that will be provided when instantiating it. For instance,
459 you could write a component that puts a frame around an image as follows:
460
461 {% highlight html %}
462 {% raw %}
463 <html>
464 <body>
465 <element name="x-myframe">
466 <template>
467 <!-- some complex wrapping happens here ... -->
468 <div class="framestyle">...<content></content>...</div>
469 </template>
470 </element>
471
472 <div is="x-myframe">
473 <!-- img will be included where we wrote <content> above -->
474 <img src="...">
475 </div>
476 </body>
477 </html>
478 {% endraw %}
479 {% endhighlight %}
480
481 * Alternative MDV conditional and listing constructs. Instead of using a
482 `<template>` tags, you will be able to use `instantiate` and
483 `iterate` attributes directly on any element. This is important because in
484 some parts of the HTML is not valid to write `<template>` tags. For example,
485 this feature will make it possible to iterate on table rows and cells.
486
487 ## Developing and using Dart web components
488
489 We are making several tools available to make it easy to create and deploy
490 projects that use Dart web components. We have a compiler tool that can be run
491 offline to generate efficient code for your components. The generated code will
492 try to use the native features available in browsers, but otherwise it will
493 resort to other techniques to ensure that the semantics of Dart web components
494 are the same everywhere.
495
496 We have added integration with the Dart editor, so that changes to source files
497 can be compiled automatically in the background. We are also developing an
498 extension for Dartium that will be able to compile components on the fly as
499 you load them. Both the editor and Dartium integration will provide you with a
500 smooth edit/refresh cycle.
501
502 More details about our tools will be available soon.
503
504 ## Exploring more
505
506 There are many resources to explore and learn more about Dart web components.
507 Check out our Dartisans episode on this topic:
508
509 <iframe width="560" height="315" src="http://www.youtube.com/embed/zUdQkSwslzc" frameborder="0" allowfullscreen></iframe>
510
511 You can also follow the project in [GitHub][dwc], track and file bugs in our
512 [issue tracker][bugs], and play with other examples in our repo, like our port
513 of [TodoMVC][todomvcindwc].
514
515 If you have any questions, feel free to send us email directly at
516 [misc@dartlang.org](mailto:misc@dartlang.org).
517
518
519 [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html
520 [mdv]: http://code.google.com/p/mdv/
521 [dwc]: https://github.com/dart-lang/dart-web-components/
522 [bugs]: https://github.com/dart-lang/dart-web-components/issues
523 [backbone]: http://backbonejs.org/
524 [angular]: http://angularjs.org/
525 [ember]: http://emberjs.com/
526 [todomvcindwc]: https://github.com/dart-lang/dart-web-components/tree/master/exa mple/todomvc
527 [watcher]: http://dart-lang.github.com/dart-web-components/docs/watcher.html
Jennifer Messerly 2012/10/10 02:37:20 eventually, might want to create a Jekyll module f
Siggi Cherem (dart-lang) 2012/10/10 17:20:55 yeah - not sure how general we can make them since
Jennifer Messerly 2012/10/10 17:48:03 yeah, good point. you'd need some way to set the "
528 [watcher.dispatch]: http://dart-lang.github.com/dart-web-components/docs/watcher .html#dispatch
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698