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