| Index: src/site/docs/tutorials/polymer-intro/index.markdown
|
| diff --git a/src/site/docs/tutorials/polymer-intro/index.markdown b/src/site/docs/tutorials/polymer-intro/index.markdown
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0824abd3dd3fe8f544823137c911eae95c69aded
|
| --- /dev/null
|
| +++ b/src/site/docs/tutorials/polymer-intro/index.markdown
|
| @@ -0,0 +1,497 @@
|
| +---
|
| +layout: default
|
| +title: "Define a Custom Element"
|
| +description: "Create a custom HTML element using Polymer."
|
| +has-permalinks: true
|
| +tutorial:
|
| + id: polymer-intro
|
| +next: fetchdata
|
| +next-title: "Fetch Data Dynamically"
|
| +prev: shared-pkgs
|
| +prev-title: "Install Shared Packages"
|
| +---
|
| +
|
| +{% capture whats_the_point %}
|
| +
|
| +* Polymer.dart is the next evolution of Web UI.
|
| +* Everything in Polymer.dart is an element.
|
| +* Custom elements provide semantically meaningful encapsulation.
|
| +* Use Polymer.dart to build custom elements.
|
| +* Bind Dart data to HTML elements.
|
| +* Declaratively bind event handlers to elements.
|
| +
|
| +{% endcapture %}
|
| +
|
| +{% capture sample_links %}
|
| +
|
| +<p>
|
| +Get the source code for the samples featured in this target:</p>
|
| +
|
| +<ul>
|
| + <li>
|
| + <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch"
|
| + target="_blank">stopwatch</a>
|
| + </li>
|
| +</ul>
|
| +
|
| +{% endcapture %}
|
| +
|
| +{% capture content %}
|
| +
|
| +<div class="tute-target-title">
|
| +<h1>{{page.title}}</h1>
|
| +<h3>Create a custom HTML element using Polymer</h3>
|
| +</div>
|
| +
|
| +A custom element is an HTML element you can define yourself,
|
| +encapsulating appearance and/or behavior
|
| +within semantically meaningful HTML.
|
| +
|
| +<aside class="alert">
|
| + Custom elements are one feature of
|
| +<a href="http://www.polymer-project.org/"
|
| + target="_blank">Polymer</a>,
|
| +a new type of library for the web based on Web Components.
|
| +<a href="http://www.dartlang.org/polymer-dart/"
|
| + target="_blank">Polymer.dart</a>
|
| +is the Dart implementation of Polymer.
|
| +(Note: Polymer supersedes Web UI.)
|
| +</aside>
|
| +
|
| +* [An example](#an-example)
|
| +* [Installing Polymer.dart](#getting-polymer-dart)
|
| +* [Including Polymer.dart in your application](#bootstrap)
|
| +* [Instantiating a custom element](#instantiating)
|
| +* [Defining a custom element](#define-element)
|
| +* [Providing a template for the custom element](#providing-a-template)
|
| +* [Providing a script for the custom element](#providing-a-script)
|
| +* [Overiding life-cycle methods](#life-cycle-methods)
|
| +* [Using data binding](#data-binding)
|
| +* [Setting up event handlers declaratively](#event-handlers)
|
| +* [Querying the Shadow DOM](#in-the-shadows)
|
| +* [Styling a custom element](#scoped-css)
|
| +* [Other resources](#other-resources)
|
| +
|
| +##An example
|
| +
|
| +In the example running below,
|
| +the LemonChiffon area outlined in black
|
| +is a custom element implemented using Polymer.
|
| +
|
| +<strong>Try it!</strong>
|
| +Start and stop the stopwatch.
|
| +Reset the stopwatch to 00:00 using the **Reset** button.
|
| +
|
| +<iframe class="running-app-frame"
|
| + style="height:220px;width:230px;"
|
| + src="examples/stopwatch/out/web/index.html">
|
| +</iframe>
|
| +
|
| +To place this custom element on an HTML page,
|
| +import the file with the custom element definition
|
| +and use the name of the element as an HTML tag:
|
| +
|
| +{% prettify html %}
|
| +<link rel="import" href="tute_stopwatch.html">
|
| +...
|
| +<tute-stopwatch></tute-stopwatch>
|
| +{% endprettify %}
|
| +
|
| +The counting text, the three buttons along with their actions,
|
| +and the style are all contained within the custom element.
|
| +The definition of the custom element encapsulates and
|
| +hides the implementation details,
|
| +which as the user of the element, you care nothing about.
|
| +
|
| +When you use developer tools to inspect the element,
|
| +you see just the custom element's begin and end tags.
|
| +
|
| +
|
| +
|
| +With custom elements, you can easily create new kinds of elements
|
| +that have semantically meaningful tags and that are easy to share,
|
| +reuse, and read.
|
| +
|
| +###Overview of the example files
|
| +
|
| +Three main source files implement the Stopwatch example:
|
| +
|
| +<dl>
|
| + <dt>
|
| + <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/index.html" target="_blank">index.html</a>
|
| + </dt>
|
| + <dd>
|
| + The primary HTML file for the app.
|
| + Includes the Polymer bootstrap script and instantiates the custom element.
|
| + </dd>
|
| + <dt>
|
| + <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.html" target="_blank">tute_stopwatch.html</a>
|
| + </dt>
|
| + <dd>
|
| + The HTML code that defines the custom element.
|
| + </dd>
|
| + <dt>
|
| + <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.dart" target="_blank">tute_stopwatch.dart</a>
|
| + </dt>
|
| + <dd>
|
| + The Dart class that implements the custom element.
|
| + </dd>
|
| +</dl>
|
| +
|
| +The following diagram shows the structure of the example
|
| +app and its use of custom elements.
|
| +
|
| +
|
| +
|
| +##Installing Polymer.dart {#getting-polymer-dart}
|
| +
|
| +To use the features provided by Polymer.dart,
|
| +you need to install the Polymer package.
|
| +If you are unfamiliar with installing packages,
|
| +refer to
|
| +<a href="/docs/tutorials/shared-pkgs/">Install Shared Packages</a>,
|
| +which describes the process in detail.
|
| +
|
| +In brief, to install the Polymer package:
|
| +
|
| +* In the application's `pubspec.yaml` file,
|
| +add the package to the list of dependencies
|
| +by adding the package name, `polymer`, to the list.
|
| +YAML is whitespace-sensitive,
|
| +so take care to indent the package name as shown:
|
| +
|
| + 
|
| +
|
| +* Run `pub install`,
|
| +which recursively installs the polymer.dart package
|
| +and all the packages that it depends on.
|
| +If you are using Dart Editor,
|
| +when you save pubspec.yaml
|
| +the editor automatically runs `pub install` for you.
|
| +If you are using command line tools,
|
| +you can run it with the command `pub install`.
|
| +
|
| +##Including Polymer.dart in your application {#bootstrap}
|
| +
|
| +To use Polymer.dart features such as custom elements,
|
| +you need to include Polymer in both
|
| +the HTML side and the Dart side of your app.
|
| +
|
| +* In the primary HTML file for your app,
|
| +include `packages/polymer/boot.js`
|
| +in the <head> section.
|
| +When using this script,
|
| +you do not need to define a top-level `main()` function,
|
| +although you can.
|
| +**Note:** Use this script instead of `packages/browser/dart.js`.
|
| +
|
| + 
|
| +
|
| +* In your Dart code, import the Polymer library:
|
| +
|
| + 
|
| +
|
| +##Instantiating a custom element {#instantiating}
|
| +
|
| +To create an instance of a custom element,
|
| +use the name of the custom element just as you would any normal HTML tag.
|
| +In this example, the tag name is `tute-stopwatch`.
|
| +
|
| +
|
| +
|
| +Using best practices,
|
| +the custom element definition is in a separate file.
|
| +Use `link [rel="import"]` to import the HTML definition file as shown.
|
| +
|
| +##Defining a custom element {#define-element}
|
| +
|
| +The definition for the <tute-stopwatch> element is
|
| +in
|
| +<a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.html" target="_blank">tute_stopwatch.html</a>.
|
| +A custom element definition should be in its own
|
| +source file so that it can be included by other files.
|
| +An HTML file that contains the definition for a custom element
|
| +does not need <html>, <head>, or <body> tags.
|
| +
|
| +To define a custom element,
|
| +use the <polymer-element> tag and provide a name.
|
| +
|
| +{% prettify html %}
|
| +<polymer-element name="tute-stopwatch">
|
| + ...
|
| +</polymer-element>
|
| +{% endprettify %}
|
| +
|
| +A custom element name must have at least one hyphen (`-`).
|
| +We advise using an identifiable prefix to
|
| +avoid naming conflicts with elements shared by others
|
| +and to help identify the project from which the element originates.
|
| +For example, for tutorial custom elements, we use the prefix `tute`.
|
| +
|
| +Within the <polymer-element> tag,
|
| +you can provide a template (appearance) and a script (behavior).
|
| +UI widgets, like our Stopwatch example,
|
| +typically have both a template and a script,
|
| +but neither is required.
|
| +A custom element with a script and no template is purely functional.
|
| +A custom element with a template and no script is purely visual.
|
| +
|
| +{% prettify html %}
|
| +<polymer-element name="tute-stopwatch">
|
| + <template>
|
| + ...
|
| + </template>
|
| + <script type="application/dart" src="tute_stopwatch.dart">
|
| + </script>
|
| +</polymer-element>
|
| +{% endprettify %}
|
| +
|
| +<dl>
|
| + <dt> <template> </dt>
|
| + <dd>
|
| + Describes the custom element's structure—its user interface.
|
| + The template comprises any valid HTML code within the <template> tag.
|
| + When the custom element is instantiated,
|
| + the instance is created from the template.
|
| + The template can include CSS styles within a <style> tag.
|
| + </dd>
|
| +
|
| + <dt> <script> </dt>
|
| + <dd markdown="1"> Specifies a Dart script.
|
| + For custom elements, the Dart script is a Dart class
|
| + that implements the behavior of the element.
|
| + The class typically overrides some
|
| + life-cycle methods and provides event handlers
|
| + that join the UI with its programmatic behavior.
|
| + In this example, the script is in
|
| + <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.dart" target="_blank">tute_stopwatch.dart</a>.
|
| + </dd>
|
| +</dl>
|
| +
|
| +##Providing a template for the custom element {#providing-a-template}
|
| +
|
| +Here's the template code for the tute-stopwatch element:
|
| +
|
| +
|
| +
|
| +The tute-stopwatch template uses a <style> tag, which is optional.
|
| +These styles are scoped; they affect only
|
| +the appearance of the custom element and the elements it contains.
|
| +More about scoped CSS in [Styling a custom element](#scoped-css).
|
| +
|
| +The rest of the code within the <template> tag
|
| +is normal HTML, with two exceptions:
|
| +
|
| +|---|---|
|
| +| `{``{``counter}}` | Uses a Polymer syntax to [bind Dart data](#data-binding) to the HTML page. The double curly braces are commonly known as a "double mustache". |
|
| +| `on-click` | Uses Polymer [declarative event mapping](#event-handlers), which allows you to set up event handlers for a UI element. `on-click` sets up an event handler for mouse clicks. Polymer has mappings for other event types, such as `on-change` for input change events. |
|
| +{: .table}
|
| +
|
| +Let's take a look at the structure of the Dart code
|
| +before we get into the details of data binding, event handlers,
|
| +and scoped CSS.
|
| +
|
| +##Providing a script for the custom element {#providing-a-script}
|
| +
|
| +On the Dart side, a class implements the behavior of the custom element.
|
| +You associate the Dart class with the custom element using the `@CustomTag`
|
| +annotation and the name of the custom element.
|
| +
|
| +
|
| +
|
| +This diagram gives an overview of the TuteStopwatch class:
|
| +
|
| +
|
| +
|
| +Any Dart class that backs a Polymer element must subclass PolymerElement.
|
| +If you want to use data binding, the class must also use ObservableMixin.
|
| +
|
| +{% comment %}
|
| +[xx: more about PolymerElement]
|
| +[xx: more about ObservableMixin]
|
| +{% endcomment %}
|
| +
|
| +The class can respond to life-cycle milestones
|
| +by overriding [life-cycle methods](#life-cycle-methods).
|
| +For example, the TuteStopwatch class overrides the `inserted()`
|
| +method—which is called when the element is inserted
|
| +into the DOM—to initialize the app.
|
| +
|
| +The `start()` method is an event handler for the **Start** button.
|
| +The event handler is declaratively connected to the button.
|
| +Refer to [Setting up event handlers declaratively](#event-handlers) to see how.
|
| +
|
| +##Overriding life-cycle methods {#life-cycle-methods}
|
| +
|
| +A custom element has four life-cycle methods
|
| +that it can override:
|
| +
|
| +|---|---|
|
| +| `created()` | Called when an instance of a custom element is created. |
|
| +| `inserted()` | Called when an instance of a custom element is inserted into the DOM. |
|
| +| `removed()` | Called when an instance of a custom element is removed from the DOM. |
|
| +| `attributeChanged()` | Called when an attribute, such as `class`, of an instance of the custom element is added, changed, or removed. |
|
| +{: .table}
|
| +
|
| +You can override any of these life-cycle methods.
|
| +The overriding method
|
| +*must* call the super class method first.
|
| +
|
| +The Stopwatch app overrides the `inserted()` method because it
|
| +needs a reference to each of the three buttons
|
| +so that it can enable and disable them.
|
| +When a tute-stopwatch custom element is inserted into the DOM
|
| +the buttons have been created, so the references to them
|
| +will be available when the inserted() method is called.
|
| +You'll notice that it gets the buttons by
|
| +[querying the custom element's shadow root](#in-the-shadows).
|
| +
|
| +{% prettify dart %}
|
| +void inserted() {
|
| + super.inserted();
|
| + startButton = getShadowRoot('tute-stopwatch').query('#startButton');
|
| + stopButton = getShadowRoot('tute-stopwatch').query('#stopButton');
|
| + resetButton = getShadowRoot('tute-stopwatch').query('#resetButton');
|
| +
|
| + stopButton.disabled = true;
|
| + resetButton.disabled = true;
|
| +}
|
| +{% endprettify %}
|
| +
|
| +##Using data binding {#data-binding}
|
| +
|
| +In the HTML definition of a custom element,
|
| +use double curly brackets to embed Dart data into the webpage.
|
| +In your Dart code, use the `@observable` annotation
|
| +to mark the embedded data.
|
| +Here, the data is a string called `counter`.
|
| +
|
| +
|
| +
|
| +The tute-stopwatch element uses a periodic
|
| +<a href="https://api.dartlang.org/dart_async/Timer.html" target="_blank">Timer</a>
|
| +to fire an event every second.
|
| +When the Timer fires, it calls the `updateTimer()` method,
|
| +which modifies the `counter` string.
|
| +Polymer takes care of updating the HTML page with the new string.
|
| +
|
| +This type of binding is called _one-way data binding_
|
| +because the data can change only on the Dart side.
|
| +Polymer also supports two-way data binding.
|
| +In two-way data binding, when data changes on the HTML side—for example
|
| +with an input element—the value in the Dart code changes to match.
|
| +
|
| +You can use expressions within the double curly brackets.
|
| +<a href="http://pub.dartlang.org/packages/polymer_expressions"
|
| + target="_blank">Polymer expressions</a>
|
| +provide the default syntax. Examples of allowable expressions include:
|
| +
|
| +|---|---|
|
| +| `{``{``myObject.aProperty}}` | Property access. |
|
| +| `{``{``!empty}}` | Operators, like the logical not operator. |
|
| +| `{``{``myList[3]}}` | List indexing. |
|
| +| `{``{``myFilter()}}` | Data filtering. |
|
| +{: .table}
|
| +
|
| +##Setting up event handlers declaratively {#event-handlers}
|
| +
|
| +This example has three buttons, each
|
| +with an event handler that is written in Dart,
|
| +but attached to the button declaratively from HTML.
|
| +
|
| +
|
| +
|
| +In HTML, use the `on-click` attribute
|
| +to attach a mouse click handler to an HTML element.
|
| +The value of the attribute must be the name of a method
|
| +in the class that implements the custom element.
|
| +When the user clicks the button, the specified method is called
|
| +with three parameters:
|
| +
|
| +* An
|
| +<a href="https://api.dartlang.org/dart_html/Event.html" target="_blank">Event</a>
|
| +that contains information about the event,
|
| +such as its type and when it occurred.
|
| +
|
| +* The _detail_ object can provide additional, event-specific information.
|
| +
|
| +* The <a href="https://api.dartlang.org/dart_html/Node.html" target="_blank">Node</a>
|
| +that fired the event—the **Start** button in this case.
|
| +
|
| +You can attach event handlers for other kinds of events.
|
| +For example, you can use `on-change` to handle events for input text elements
|
| +when the text changes.
|
| +
|
| +Refer to
|
| +[Declarative event mapping](http://www.polymer-project.org/polymer.html#declarative-event-mapping)
|
| +for further details.
|
| +
|
| +##Querying the shadow root {#in-the-shadows}
|
| +
|
| +The Shadow DOM is key to encapsulation.
|
| +The DOM subtree for a custom element is
|
| +hidden from outside of the custom element.
|
| +
|
| +
|
| +
|
| +You can programmatically get items from the Shadow DOM
|
| +by querying a custom element's _shadow root_—a
|
| +special node from which an instance of a custom element is rendered.
|
| +
|
| +{% prettify dart %}
|
| +startButton = getShadowRoot('tute-stopwatch').query('#startbutton');
|
| +stopButton = getShadowRoot('tute-stopwatch').query('#stopbutton');
|
| +resetButton = getShadowRoot('tute-stopwatch').query('#resetbutton');
|
| +{% endprettify %}
|
| +
|
| +Call `getShadowRoot()` with the name of the custom element.
|
| +The `getShadowRoot()` method returns the shadow root element
|
| +for this instance of the specified element.
|
| +Use `query()` with a CSS selector to get the element(s) of interest.
|
| +
|
| +Note that this code uses `query()` to get each button by ID.
|
| +By querying the shadow root object rather than the DOM,
|
| +you are guaranteed to get the objects from within the custom element,
|
| +not from anywhere else on the page.
|
| +
|
| +##Styling a custom element {#scoped-css}
|
| +
|
| +You can optionally include CSS styles for your custom element
|
| +that apply only to the contents of the custom element.
|
| +
|
| +
|
| +
|
| +The `@host` rule allows you to target and style an element internally,
|
| +from within its definition.
|
| +The `:scope` pseudo-class refers to the custom element itself.
|
| +The only selectors that work in `@host` are those targeting the host element itself.
|
| +So you don't need to worry about naming conflicts on the page.
|
| +Any CSS selectors within the template need to be unique only within the template.
|
| +
|
| +For further details about styling custom elements,
|
| +refer to
|
| +[A Guide to Styling Elements](http://www.polymer-project.org/articles/styling-elements.html)
|
| +
|
| +##Other resources
|
| +
|
| +Use these other resources to learn more about Polymer:
|
| +
|
| +* The tutorial
|
| +<a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web"
|
| + target="_blank">github repo</a>
|
| + contains many examples that use Polymer,
|
| + including samples that have been converted from Web UI.
|
| +
|
| +* The
|
| +<a href="http://www.dartlang.org/polymer-dart/"
|
| + target="_blank">Polymer.dart</a> homepage provides information
|
| + specific to the Dart port of the Polymer project.
|
| +
|
| +* The Polymer project website
|
| +<a href="http://www.polymer-project.org/"
|
| + target="_blank">polymer-project.org</a>
|
| + contains information about the Polymer project as a whole.
|
| +
|
| +{% endcapture %}
|
| +
|
| +{% include tutorial.html %}
|
|
|