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..b2d0e853ea1458b7342d5cac6b7817b99467d7c3 |
--- /dev/null |
+++ b/src/site/articles/dart-web-components/index.markdown |
@@ -0,0 +1,528 @@ |
+--- |
+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 |
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
|
+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, and another document with instructions on how to use the Dart web |
+component tools. |
+ |
+## 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 |
+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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/helloworld.html %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/helloworld.html.html %} |
+{% 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 [watcher.dart][watcher] library |
+(included with 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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/counter.html %} |
+{% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/explainer/counter.html.html %} |
+{% endcodesample %} |
+ |
+The code manually invokes [watchers.dispatch()][watcher.dispatch] to make a |
+change visible to the 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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/twoway.html %} |
+{% 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 extent, feature and design |
+parity with MDV. For this reason, we try to match the same syntax of their |
+template language. MDV restricts data-binding 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 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. |
+ |
+### 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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/matchstrings.html %} |
+{% 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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/fruitsearch.html %} |
+{% 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 %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/clickcount.html %} |
+{% 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 data bindings, two-way data bindings, |
+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-click-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 defines a component whose visual apperance is declared 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 HTML elements, their |
+declaration indicates which element 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 HTML element 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-click-counter></x-click-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-click-counter"></div> |
+ <script type="application/dart"> |
+ main(){} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/countcomponent.html %} |
+{% 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-click-counter" data-value="count: myNumber"></div> |
+ <div is="x-click-counter" data-value="count: 5"></div> |
+ <script type="application/dart"> |
+ int myNumber = 12; |
+ main(){} |
+ </script> |
+</body></html> |
+{% endraw %} |
+{% endhighlight %} |
+{% url https://github.com/dart-lang/dart-web-components/blob/master/example/explainer/countcomponent5.html %} |
+{% 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 import other components using `<link |
+rel="components">` tags. For example, suppose we created a file |
+`clickcounter.html` that contains the declaration of the click-counter component |
+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-click-counter" data-value="count: myNumber"></div> |
+ <div is="x-click-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. |
+ |
+## 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 |
+[issue tracker][bugs], and play with other examples in our repo, like our port |
+of [TodoMVC][todomvcindwc]. |
+ |
+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 |
+[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 "
|
+[watcher.dispatch]: http://dart-lang.github.com/dart-web-components/docs/watcher.html#dispatch |