Index: src/site/articles/dart-web-components/index.markdown |
diff --git a/src/site/articles/dart-web-components/index.markdown b/src/site/articles/dart-web-components/index.markdown |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6d6428f1179aa816b39eda2b0eaf5038a7d36ffe |
--- /dev/null |
+++ b/src/site/articles/dart-web-components/index.markdown |
@@ -0,0 +1,519 @@ |
+--- |
+layout: default |
+title: "Dart Web Components" |
+rel: |
+ author: siggi-cherem |
+description: "A brief introduction to Dart web components." |
+has-permalinks: true |
+--- |
+ |
+# {{ page.title }} |
+_Written by Siggi Cherem<br /> |
+October 2012 <br /> |
+Updated: October 2012_ |
+ |
+{% comment %} |
+ |
+README --- General notes about editing this file: |
+ |
+* This file is processed by liquid, which evaluates {{ var }} and removes the |
+\{\{ and \}\} symbols from the code. Because we use \{\{\}\} in our template |
+expressions, we need to escape them in a special way. Unfortunately using |
+\{\{\}\} within code makes the backslash show up. There are 2 ways to work |
+around this: |
+ * Doing {{'{{'}}: lyquid evaluates it as a string expression returning \{\{. |
+ * Using \{\% raw \%\} blocks. |
+ |
+* the codesample blocks are an extension added to jekyll written as 'liquid' |
+blocks. The meaning of a block like this: |
+ \{\% codesample 80 \%\} |
+ |
+ text |
+ \{\% sample 10 20 url \%\} |
+ \{\% endcodesample \%\} |
+is that we'll create a table, the first colum will have sample source code (in |
+this case "text"). This code can have a \{\% highlight \%\} section, but other |
+than that, no markdown is supported here :(. The column width is specified as |
+the first argument of the codesample tag above it (in this example 80 means |
+80%). The \{\% sample \%\} tag defines the width, height, and url for an iframe |
+that will contain the runnining version of the code sample. |
+ |
+{% endcomment %} |
+ |
+Dart web components provide a templating, data binding, and encapsulation, to |
+help you write web applications at scale. An early version is available in the |
+[dart-web-components project][dwc]. |
+ |
+Many UI frameworks exist for writing web apps in |
+JavaScript -- for example [backbone], [ember.js][ember], and [angularjs][angular]. |
+Recently, the web community has been pushing to include some of the common ideas |
+of these frameworks directly into the browser platform. A result has |
+been added features like shadow DOM and [web components][wc], and other |
+experimental and cool ideas like [model-driven views][mdv] (MDV). |
+ |
+Dart web components combine the ideas of web components and MDV, adapting them |
+to work well with Dart. Dart web components take advantage of advanced browser |
+features when possible, emulating missing features when necessary. |
+ |
+In this article, we'll walk through some examples that illustrate how to write |
+and use Dart web components. Soon we'll be creating a document with a detailed |
+specification (link TBR), and another document with instructions on how to use |
+the Dart web component tools (link TBR). |
+ |
+## MDV templates in Dart |
+ |
+Most UI frameworks provide some form of templating to declare views with a |
+succinct declarative syntax. Dart web components closely follow the MDV syntax, |
+which is basically HTML with small extensions to enable the following features: |
+ |
+ * **One-way data binding**: Embed data into your UI |
+ * **Two-way data binding**: Keep data in sync with UI changes |
+ * **Events listeners**: Easily attach code that reacts to UI events |
+ * **Conditionals**: Selectively show parts of the UI |
+ * **Loops**: Construct lists and tables by iterating over collections |
+ |
+We made some changes to make sure that using Dart with MDV feels natural, but |
+otherwise all the concepts from MDV are available here. Let's take a look at |
+examples for each of these features. |
+ |
+### One-way data bindings |
+ |
+You can inject data in your template using `{{'{{'}}expression}}`. The |
+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.
|
+top-level variable `dataValue` is injected in the page automatically. The right |
+column shows the app generated from this code running in an iframe. |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div>Hello {{dataValue}}!</div> |
+ <script type="application/dart"> |
+ String dataValue; |
+ main() { |
+ var today = new Date.now(); |
+ dataValue = 'world ${today.year}-${today.month}-${today.day}'; |
+ } |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/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.
|
+{% endcodesample %} |
+ |
+The template expression we just saw above is what we call a **one-way data |
+binding**. Like in many other UI libraries and frameworks, we automatically |
+watch for changes in your data and ensure the UI is up-to-date whenever the data |
+changes. |
+ |
+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
|
+the dart web components package). You can listen for changes and notify everyone |
+when changes might occur. The following example illustrates how you would |
+manually use this library: |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div>Hello counter: {{count}}</div> |
+ <script type="application/dart"> |
+ import 'dart:html'; |
+ import 'package:web_components/watcher.dart' as watchers; |
+ int count; |
+ main() { |
+ count = 0; |
+ window.setInterval(() { |
+ count++; |
+ watchers.dispatch(); |
+ }, 1000); |
+ } |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/counter.html.html %} |
+{% endcodesample %} |
+ |
+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.
|
+UI. Every now and then it is useful to access watchers directly, but we have |
+found that we often don't have to manually write these calls. In particular, |
+Dart web components will automatically make the dispatch call when using |
+common features like two-way binding and attaching event listeners. |
+ |
+### Two-way data bindings |
+ |
+Two-way data bindings lets us define that we want a DOM element's value |
+(typically an input box or a check box) to be kept in sync with the value of a |
+Dart variable. The following example creates a two way binding between `str` and |
+`input.value`. We declare this binding by writing the attribute |
+`data-bind="value:str"`. |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div> |
+ Input: |
+ <input type="text" data-bind="value:str" placeholder="type something here"> |
+ <div> Value: {{str}}</div> |
+ <div> Length: {{str.length}}</div> |
+ </div> |
+ <script type="application/dart"> |
+ String str = ''; |
+ main() {} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/twoway.html.html %} |
+{% endcodesample %} |
+ |
+This is a simple example where Dart web components automatically dispatch |
+events for data-model changes. In particular, whenever you update the value of |
+the text box, the string and it's length will be updated in other parts of the |
+UI. |
+ |
+### Data-binding expressions |
+ |
+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
|
+parity with MDV. For this reason, we try to match the same syntax of their |
+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.
|
+expressions to an expression language containing variables, field dereferences, |
+and array accesses. This means that expressions in MDV templates would likely be |
+valid Dart and valid JavaScript as well. That also means that advanced Dart expressions |
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.
|
+are not valid between `{{'{{'}}expressions}}`, however you can always hide |
+complex expressions under a getter in Dart and use the getter property within |
+the template. |
+ |
+A full specification of the expression syntax will be available soon in our |
+[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.
|
+ |
+### Conditionals |
+ |
+Template conditionals allow you to selectively activate parts of the UI. We |
+write a conditional by wrapping a portion of the UI in a `<template>` tag and |
+writing the condition in an attribute of the form `instantiate="if expr"`. For |
+instance, the following example only shows `They match!` when both input boxes |
+have the same text: |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div> |
+ <div> Input1: <input type="text" data-bind="value:str1"></div> |
+ <div> Input2: <input type="text" data-bind="value:str2"></div> |
+ <template instantiate="if str1 == str2"> |
+ <div>They match!</div> |
+ </template> |
+ </div> |
+ <script type="application/dart"> |
+ String str1 = ''; |
+ String str2 = ''; |
+ main() {} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/matchstrings.html.html %} |
+{% endcodesample %} |
+ |
+### Loops |
+ |
+Template loops allow us to iterate over iterable Dart collections. The following |
+example shows a fun little app that has search as you type. We use the two-way |
+data binding to store the `query` string, then we compute a filtered set of |
+results and display it using a looping construct. |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div> |
+ <span>Search for something:</span> |
+ <input type="text" data-bind="value:query"> |
+ <div> |
+ <template instantiate='if noMatches'><span>No matches</span></template> |
+ <template instantiate='if !noMatches'><span>Top results:</span></template> |
+ </div> |
+ <div><ul> |
+ <template iterate='fruit in results'> |
+ <li>{{fruit}}</li> |
+ </template> |
+ </ul></div> |
+ </div> |
+ <script type="application/dart"> |
+ String query = ''; |
+ List<String> values = const [ 'Apple', 'Apricot', 'Avocado', 'Banana', |
+ 'Blackberry', 'Blackcurrant', 'Blueberry', 'Currant', 'Cherry', |
+ 'Clementine', 'Date', 'Durian', 'Fig', 'Gooseberry', 'Grape', |
+ 'Grapefruit', 'Guava', 'Huckleberry', 'Kiwi', 'Lemon', 'Lime', |
+ 'Lychee', 'Mandarine', 'Mango', 'Cantaloupe', 'Honeydew melon', |
+ 'Nectarine', 'Orange', 'Peach', 'Pear', 'Plum', 'Pineapple', |
+ 'Pomegranate', 'Raspberry', 'Redcurrant', 'Star fruit', 'Strawberry', |
+ 'Tangerine', 'Tomato', 'Watermelon']; |
+ |
+ List<String> get results { |
+ var res = values.filter( |
+ (v) => v.toLowerCase().contains(query.toLowerCase())); |
+ if (res.length > 20) { |
+ res.length = 20; |
+ res.add('... and many more'); |
+ } |
+ return res; |
+ } |
+ |
+ bool get noMatches => results.isEmpty(); |
+ |
+ main() {} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 600px http://dart-lang.github.com/dart-web-components/example/explainer/fruitsearch.html.html %} |
+{% endcodesample %} |
+ |
+ |
+### Listen to UI events |
+ |
+Templates also gives us a succinct way to listen for arbitrary UI events and |
+associate those events with Dart code. We do this by using `data-action` |
+attributes. Here is an example that listens for click events: |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <div> |
+ <button data-action="click:increment">Click me</button> |
+ <span>(click count: {{count}})</span> |
+ </div> |
+ <script type="application/dart"> |
+ int count = 0; |
+ void increment(e) { count++; } |
+ main() {} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/clickcount.html.html %} |
+{% endcodesample %} |
+ |
+ |
+### Templating summary |
+ |
+Templates solve one part of the problem in building web applications: reducing |
+the amount of boilerplate code that is used to set up a typical |
+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.
|
+and data-action listeners, help reduce the need for manually creating controller |
+objects that do these bindings by hand. If we combine bindings, conditionals, |
+and loops, we have a formula to create simple and sophisticated views in a |
+declarative fashion. |
+ |
+However, templating alone is not enough. We need mechanisms to encapsulate and |
+abstract views so we can scale to build larger web apps. This is were we need |
+web components. |
+ |
+## Web components in Dart |
+ |
+Web components provide a way to create encapsulated reusable views, which will |
+be useful to build medium and large applications. A web component basically |
+includes a view, some data, and behavior. In our case, views are described in |
+terms of templates, while data and behavior are written directly in Dart. |
+ |
+### Declaring a component |
+ |
+Web components are declared using a special `<element>` tag. For example, we can |
+take the click-count example above and make it a component as follows: |
+ |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <element name="x-counter" constructor="CounterComponent" extends="div"> |
+ <template> |
+ <div> |
+ <button data-action="click:increment">Click me</button> |
+ <span>(click count: {{count}})</span> |
+ </div> |
+ </template> |
+ <script type="application/dart"> |
+ import 'package:web_components/web_component.dart'; |
+ |
+ class CounterComponent extends WebComponent { |
+ int count = 0; |
+ void increment(e) { count++; } |
+ } |
+ </script> |
+ </element> |
+<!-- more below... --> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+ |
+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.
|
+under the child `<template>` tag, and whose behavior code is embedded or sourced |
+by the child `<script>` tag. |
+ |
+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.
|
+indicates which DOM node they extend from using the `extends` attribute. The |
+attribute `constructor="CounterComponent"` indicates that this component's |
+behavior is defined in the `CounterComponent` class. Today, this class must |
+extend from `WebComponent`, but in the future it will be possible to extend |
+directly from the DOM Node that we declared in the `extends` attribute. For |
+instance, `class CounterComponent extends DivElement ...`. |
+ |
+The `<element>` tag also declares the component's name with the `name` |
+attribute. This name will be used to instantiate this component later on. |
+ |
+### Instantiating a component |
+ |
+Instantiating a component can be done in two ways: using its name as a tag, e.g. |
+`<x-counter></x-counter>` or using setting the `is` attribute on the |
+tag that the component extends from. For example, |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <!-- ... element declared as above --> |
+ <div is="x-counter"></div> |
+ <script type="application/dart"> |
+ main(){} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/countcomponent.html.html %} |
+{% endcodesample %} |
+ |
+ |
+### Passing data to a component |
+ |
+All of the public fields in a component declaration can be initialized directly |
+when we instantiate a component. We can do this by writing a special |
+`data-value` attribute in the HTML. For instance, the following example |
+instantiates two click-counter components (declared just like above), but |
+initializes the `count` field of the component to a different value each time. |
+ |
+{% codesample 90 %} |
+{% highlight html %} |
+{% raw %} |
+<html><body> |
+ <!-- ... element declared as above --> |
+ <div is="x-counter" data-value="count: myNumber"></div> |
+ <div is="x-counter" data-value="count: 5"></div> |
+ <script type="application/dart"> |
+ int myNumber = 12; |
+ main(){} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/countcomponent5.html.html %} |
+{% endcodesample %} |
+ |
+### Working at scale |
+ |
+When developing larger web applications, it is really useful to be able to split |
+the work and divide pieces of your application in multiple files. It is also |
+useful to create reusable components that you embed in several places of your |
+application or even across several applications. |
+ |
+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.
|
+rel="components">` tags. For example, suppose we created a file |
+`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.
|
+as we had above. Then, our last example could be rewritten as follows: |
+ |
+{% highlight html %} |
+{% raw %} |
+<html> |
+ <head> |
+ <link rel="components" href="clickcounter.html"> |
+ </head> |
+ <body> |
+ <div is="x-counter" data-value="count: myNumber"></div> |
+ <div is="x-counter" data-value="count: 5"></div> |
+ <script type="application/dart"> |
+ int myNumber = 12; |
+ main(){} |
+ </script> |
+ </body> |
+</html> |
+{% endraw %} |
+{% endhighlight %} |
+ |
+### Upcoming features |
+ |
+We are still adding features and making changes to Dart web components. Here are |
+some of the features we are working on: |
+ |
+ * Support for sub-components. Using a special `<content>` tag, a component |
+ can embed nodes that will be provided when instantiating it. For instance, |
+ you could write a component that puts a frame around an image as follows: |
+ |
+{% highlight html %} |
+{% raw %} |
+<html> |
+ <body> |
+ <element name="x-myframe"> |
+ <template> |
+ <!-- some complex wrapping happens here ... --> |
+ <div class="framestyle">...<content></content>...</div> |
+ </template> |
+ </element> |
+ |
+ <div is="x-myframe"> |
+ <!-- img will be included where we wrote <content> above --> |
+ <img src="..."> |
+ </div> |
+ </body> |
+</html> |
+{% endraw %} |
+{% endhighlight %} |
+ |
+ * Alternative MDV conditional and listing constructs. Instead of using a |
+ `<template>` tags, you will be able to use `instantiate` and |
+ `iterate` attributes directly on any element. This is important because in |
+ some parts of the HTML is not valid to write `<template>` tags. For example, |
+ this feature will make it possible to iterate on table rows and cells. |
+ |
+## Developing and using Dart web components |
+ |
+We are making several tools available to make it easy to create and deploy |
+projects that use dart web components. We have a compiler tool that can be run |
+offline to generate efficient code for your components. The generated code will |
+try to use the native features available in browsers, but otherwise it will |
+resort to other techniques to ensure that the semantics of dart web components |
+are the same everywhere. |
+ |
+We have added integration with the Dart editor, so that changes to source files |
+can be compiled automatically in the background. We are also developing an |
+extension for dartium that will be able to compile components on the fly as |
+you load them. Both the editor and dartium integration will provide you with a |
+smooth edit/refresh cycle. |
+ |
+More details about our tools will be available soon [(link TBR)][]. |
+ |
+## Exploring more |
+ |
+There are many resources to explore and learn more about Dart web components. |
+Check out our Dartisans episode on this topic: |
+ |
+<iframe width="560" height="315" src="http://www.youtube.com/embed/zUdQkSwslzc" frameborder="0" allowfullscreen></iframe> |
+ |
+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.
|
+[issue tracker][bugs], and play with other examples in our repo, like our port |
+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.
|
+ |
+If you have any questions, feel free to send us email directly at |
+[misc@dartlang.org](mailto:misc@dartlang.org). |
+ |
+ |
+[wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html |
+[mdv]: http://code.google.com/p/mdv/ |
+[dwc]: https://github.com/dart-lang/dart-web-components/ |
+[bugs]: https://github.com/dart-lang/dart-web-components/issues |
+[backbone]: http://backbonejs.org/ |
+[angular]: http://angularjs.org/ |
+[ember]: http://emberjs.com/ |
+[todomvcindwc]: https://github.com/dart-lang/dart-web-components/tree/master/example/todomvc |