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

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: john's 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
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_
Kathy Walrath 2012/10/11 01:01:21 Delete the "Updated" line
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 a templating -> templates
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 -- -> &mdash; (no spaces around it)
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 ah, thanks :)
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
Kathy Walrath 2012/10/11 01:01:21 I told you to do this, but it's too easy to read w
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
51 like [shadow DOM][sd] and [web components][wc], and other experimental and cool
52 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
Kathy Walrath 2012/10/11 01:01:21 In this article, we'll walk -> This article walks
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
59 and use Dart web components. Soon we'll be creating a document with a detailed
Kathy Walrath 2012/10/11 01:01:21 I initially thought that "Soon" meant "In this doc
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 done.
60 specification, and another document with instructions on how to use the Dart web
61 component tools.
Kathy Walrath 2012/10/11 01:01:21 It could be helpful to stick a table of contents h
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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,
Kathy Walrath 2012/10/11 01:01:21 delete "declarative"? (it's repetitive due to the
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done. Did the latter because I wanted to emphasize
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
Kathy Walrath 2012/10/11 01:01:21 Events listeners sounds weird to me. -> Event list
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 make sure -> ensure OR be sure (to avoid repetit
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 bindings -> binding (Match the item in the list)
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 bindings -> binding
Kathy Walrath 2012/10/11 01:01:21 sd
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
147
148 Two-way data bindings lets us define that we want a DOM element's value
Kathy Walrath 2012/10/11 01:01:21 bindings -> binding
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 it's -> its (if you think of 'his' and 'hers', th
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 thanks :) - this is one where if I think about it
178 UI.
179
180 ### Data-binding expressions
Kathy Walrath 2012/10/11 01:01:21 If you look at the TOC, this isn't like the other
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 between -> within expressions}} -> expression}} g
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 correct - thank you :)
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
Kathy Walrath 2012/10/11 01:01:21 You should mention the `iterate` attribute in this
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 -> ### Event listeners
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 Templating summary -> Summary of templates (Havin
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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,
Kathy Walrath 2012/10/11 01:01:21 bindings -> binding (twice in this line; to match
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
313 and data-action listeners, help reduce the need for manually creating controller
Kathy Walrath 2012/10/11 01:01:21 , help -> help
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 -> ### Importing a component (to match the task o
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 ### -> ## (since these features are for templates
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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
Kathy Walrath 2012/10/11 01:01:21 GLOBAL: sub-component -> subcomponent (it's in th
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 wow - cool. Thanks :)
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
Kathy Walrath 2012/10/11 01:01:21 -> ## Tools for developing and using Dart web comp
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 nice - done.
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
Kathy Walrath 2012/10/11 01:01:21 ## Exploring more -> ## More information OR ## Res
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 :), fixed
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
Kathy Walrath 2012/10/11 01:01:21 like -> such as (in general, "like" is easy to mi
Siggi Cherem (dart-lang) 2012/10/11 18:26:14 Done.
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 [sd]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
520 [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html
521 [mdv]: http://code.google.com/p/mdv/
522 [dwc]: https://github.com/dart-lang/dart-web-components/
523 [bugs]: https://github.com/dart-lang/dart-web-components/issues
524 [backbone]: http://backbonejs.org/
525 [angular]: http://angularjs.org/
526 [ember]: http://emberjs.com/
527 [todomvcindwc]: https://github.com/dart-lang/dart-web-components/tree/master/exa mple/todomvc
528 [watcher]: http://dart-lang.github.com/dart-web-components/docs/watcher.html
529 [watcher.dispatch]: http://dart-lang.github.com/dart-web-components/docs/watcher .html#dispatch
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698