OLD | NEW |
---|---|
1 --- | 1 --- |
2 layout: default | 2 layout: default |
3 title: "Define a Custom Element" | 3 title: "Define a Custom Element" |
4 description: "Create a custom HTML element using Polymer." | 4 description: "Create a custom HTML element using Polymer." |
5 has-permalinks: true | 5 has-permalinks: true |
6 tutorial: | 6 tutorial: |
7 id: polymer-intro | 7 id: polymer-intro |
8 next: fetchdata | 8 next: fetchdata |
9 next-title: "Fetch Data Dynamically" | 9 next-title: "Fetch Data Dynamically" |
10 prev: shared-pkgs | 10 prev: shared-pkgs |
(...skipping 29 matching lines...) Expand all Loading... | |
40 | 40 |
41 <div class="tute-target-title"> | 41 <div class="tute-target-title"> |
42 <h1>{{page.title}}</h1> | 42 <h1>{{page.title}}</h1> |
43 <h3>Create a custom HTML element using Polymer</h3> | 43 <h3>Create a custom HTML element using Polymer</h3> |
44 </div> | 44 </div> |
45 | 45 |
46 A custom element is an HTML element you can define yourself, | 46 A custom element is an HTML element you can define yourself, |
47 encapsulating appearance and/or behavior | 47 encapsulating appearance and/or behavior |
48 within semantically meaningful HTML. | 48 within semantically meaningful HTML. |
49 | 49 |
50 <aside class="alert"> | 50 <aside class="alert alert-info"> |
51 Custom elements are one feature of | 51 Custom elements are one feature of |
52 <a href="http://www.polymer-project.org/" | 52 <a href="http://www.polymer-project.org/" |
53 target="_blank">Polymer</a>, | 53 target="_blank">Polymer</a>, |
54 a new type of library for the web based on Web Components. | 54 a new type of library for the web based on Web Components. |
55 <a href="http://www.dartlang.org/polymer-dart/" | 55 <a href="http://www.dartlang.org/polymer-dart/" |
56 target="_blank">Polymer.dart</a> | 56 target="_blank">Polymer.dart</a> |
57 is the Dart implementation of Polymer. | 57 is the Dart implementation of Polymer. |
58 (Note: Polymer supersedes Web UI.) | 58 (Note: Polymer supersedes Web UI.) |
59 </aside> | 59 </aside> |
60 | 60 |
61 * [An example](#an-example) | 61 * [An example](#an-example) |
62 * [Installing Polymer.dart](#getting-polymer-dart) | 62 * [Installing Polymer.dart](#getting-polymer-dart) |
63 * [Including Polymer.dart in your application](#bootstrap) | 63 * [Including Polymer.dart in your application](#bootstrap) |
64 * [Instantiating a custom element](#instantiating) | 64 * [Instantiating a custom element](#instantiating) |
65 * [Defining a custom element](#define-element) | 65 * [Defining a custom element](#define-element) |
66 * [Providing a template for the custom element](#providing-a-template) | 66 * [Providing a template for the custom element](#providing-a-template) |
67 * [Providing a script for the custom element](#providing-a-script) | 67 * [Providing a script for the custom element](#providing-a-script) |
68 * [Overiding life-cycle methods](#life-cycle-methods) | 68 * [Overiding life-cycle methods](#life-cycle-methods) |
69 * [Using data binding](#data-binding) | 69 * [Using data binding](#data-binding) |
70 * [Setting up event handlers declaratively](#event-handlers) | 70 * [Setting up event handlers declaratively](#event-handlers) |
71 * [Querying the Shadow DOM](#in-the-shadows) | |
72 * [Styling a custom element](#scoped-css) | 71 * [Styling a custom element](#scoped-css) |
73 * [Other resources](#other-resources) | 72 * [Other resources](#other-resources) |
73 * [What next?](#what-next) | |
74 | 74 |
75 ##An example | 75 ##An example |
76 | 76 |
77 In the example running below, | 77 In the example running below, |
78 the LemonChiffon area outlined in black | 78 the LemonChiffon area outlined in black |
79 is a custom element implemented using Polymer. | 79 is a custom element implemented using Polymer. |
80 | 80 |
81 <strong>Try it!</strong> | 81 <strong>Try it!</strong> |
82 Start and stop the stopwatch. | 82 Start and stop the stopwatch. |
83 Reset the stopwatch to 00:00 using the **Reset** button. | 83 Reset the stopwatch to 00:00 using the **Reset** button. |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 The tute-stopwatch template uses a <style> tag, which is optional. | 277 The tute-stopwatch template uses a <style> tag, which is optional. |
278 These styles are scoped; they affect only | 278 These styles are scoped; they affect only |
279 the appearance of the custom element and the elements it contains. | 279 the appearance of the custom element and the elements it contains. |
280 More about scoped CSS in [Styling a custom element](#scoped-css). | 280 More about scoped CSS in [Styling a custom element](#scoped-css). |
281 | 281 |
282 The rest of the code within the <template> tag | 282 The rest of the code within the <template> tag |
283 is normal HTML, with two exceptions: | 283 is normal HTML, with two exceptions: |
284 | 284 |
285 |---|---| | 285 |---|---| |
286 | `{``{``counter}}` | Uses a Polymer syntax to [bind Dart data](#data-binding) t o the HTML page. The double curly braces are commonly known as a "double mustach e". | | 286 | `{``{``counter}}` | Uses a Polymer syntax to [bind Dart data](#data-binding) t o the HTML page. The double curly braces are commonly known as a "double mustach e". | |
287 | `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 even t handler for mouse clicks. Polymer has mappings for other event types, such as `on-change` for input change events. | | 287 | `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 even t handler for mouse clicks. Polymer has mappings for other event types, such as `on-input` for changes to text fields. | |
288 {: .table} | 288 {: .table} |
289 | 289 |
290 Let's take a look at the structure of the Dart code | 290 Let's take a look at the structure of the Dart code |
291 before we get into the details of data binding, event handlers, | 291 before we get into the details of data binding, event handlers, |
292 and scoped CSS. | 292 and scoped CSS. |
293 | 293 |
294 ##Providing a script for the custom element {#providing-a-script} | 294 ##Providing a script for the custom element {#providing-a-script} |
295 | 295 |
296 On the Dart side, a class implements the behavior of the custom element. | 296 On the Dart side, a class implements the behavior of the custom element. |
297 You associate the Dart class with the custom element using the `@CustomTag` | 297 You associate the Dart class with the custom element using the `@CustomTag` |
298 annotation and the name of the custom element. | 298 annotation and the name of the custom element. |
299 | 299 |
300  | 300  |
301 | 301 |
302 This diagram gives an overview of the TuteStopwatch class: | 302 This diagram gives an overview of the TuteStopwatch class: |
303 | 303 |
304  | 304  |
305 | 305 |
306 Any Dart class that backs a Polymer element must subclass PolymerElement. | 306 Any Dart class that backs a Polymer element must subclass PolymerElement. |
307 If you want to use data binding, the class must also use ObservableMixin. | |
308 | 307 |
309 {% comment %} | 308 {% comment %} |
310 [xx: more about PolymerElement] | 309 [xx: more about PolymerElement] |
311 [xx: more about ObservableMixin] | |
312 {% endcomment %} | 310 {% endcomment %} |
313 | 311 |
314 The class can respond to life-cycle milestones | 312 The class can respond to life-cycle milestones |
315 by overriding [life-cycle methods](#life-cycle-methods). | 313 by overriding [life-cycle methods](#life-cycle-methods). |
316 For example, the TuteStopwatch class overrides the `inserted()` | 314 For example, the TuteStopwatch class overrides the `inserted()` |
317 method—which is called when the element is inserted | 315 method—which is called when the element is inserted |
318 into the DOM—to initialize the app. | 316 into the DOM—to initialize the app. |
319 | 317 |
320 The `start()` method is an event handler for the **Start** button. | 318 The `start()` method is an event handler for the **Start** button. |
321 The event handler is declaratively connected to the button. | 319 The event handler is declaratively connected to the button. |
(...skipping 14 matching lines...) Expand all Loading... | |
336 You can override any of these life-cycle methods. | 334 You can override any of these life-cycle methods. |
337 The overriding method | 335 The overriding method |
338 *must* call the super class method first. | 336 *must* call the super class method first. |
339 | 337 |
340 The Stopwatch app overrides the `inserted()` method because it | 338 The Stopwatch app overrides the `inserted()` method because it |
341 needs a reference to each of the three buttons | 339 needs a reference to each of the three buttons |
342 so that it can enable and disable them. | 340 so that it can enable and disable them. |
343 When a tute-stopwatch custom element is inserted into the DOM | 341 When a tute-stopwatch custom element is inserted into the DOM |
344 the buttons have been created, so the references to them | 342 the buttons have been created, so the references to them |
345 will be available when the inserted() method is called. | 343 will be available when the inserted() method is called. |
346 You'll notice that it gets the buttons by | |
347 [querying the custom element's shadow root](#in-the-shadows). | |
348 | 344 |
349 {% prettify dart %} | 345 {% prettify dart %} |
350 void inserted() { | 346 void inserted() { |
351 super.inserted(); | 347 super.inserted(); |
352 startButton = getShadowRoot('tute-stopwatch').query('#startButton'); | 348 startButton = $['startButton']; |
353 stopButton = getShadowRoot('tute-stopwatch').query('#stopButton'); | 349 stopButton = $['stopButton']; |
354 resetButton = getShadowRoot('tute-stopwatch').query('#resetButton'); | 350 resetButton = $['resetButton']; |
355 | 351 |
356 stopButton.disabled = true; | 352 stopButton.disabled = true; |
357 resetButton.disabled = true; | 353 resetButton.disabled = true; |
358 } | 354 } |
359 {% endprettify %} | 355 {% endprettify %} |
360 | 356 |
357 The code uses _automatic node finding_, a Polymer feature, | |
358 to get a reference to each button. | |
359 Every node in a custom element that is tagged with an `id` attribute | |
360 can be referenced by its ID using the syntax: `$['ID']`. | |
361 | |
361 ##Using data binding {#data-binding} | 362 ##Using data binding {#data-binding} |
362 | 363 |
363 In the HTML definition of a custom element, | 364 In the HTML definition of a custom element, |
364 use double curly brackets to embed Dart data into the webpage. | 365 use double curly brackets to embed Dart data into the webpage. |
365 In your Dart code, use the `@observable` annotation | 366 In your Dart code, use the `@observable` annotation |
366 to mark the embedded data. | 367 to mark the embedded data. |
367 Here, the data is a string called `counter`. | 368 Here, the data is a string called `counter`. |
368 | 369 |
369  | 370  |
370 | 371 |
371 The tute-stopwatch element uses a periodic | 372 The tute-stopwatch element uses a periodic |
372 <a href="https://api.dartlang.org/dart_async/Timer.html" target="_blank">Timer</ a> | 373 <a href="https://api.dartlang.org/dart_async/Timer.html" target="_blank">Timer</ a> |
373 to fire an event every second. | 374 to fire an event every second. |
374 When the Timer fires, it calls the `updateTimer()` method, | 375 When the Timer fires, it calls the `updateTimer()` method, |
375 which modifies the `counter` string. | 376 which modifies the `counter` string. |
376 Polymer takes care of updating the HTML page with the new string. | 377 Polymer takes care of updating the HTML page with the new string. |
377 | 378 |
378 This type of binding is called _one-way data binding_ | 379 This type of binding is called _one-way data binding_ |
379 because the data can change only on the Dart side. | 380 because the data can change only on the Dart side. |
380 Polymer also supports two-way data binding. | 381 Polymer also supports two-way data binding. |
381 In two-way data binding, when data changes on the HTML side—for example | 382 In two-way data binding, when data changes on the HTML side—for example |
382 with an input element—the value in the Dart code changes to match. | 383 with an input element—the value in the Dart code changes to match. |
384 For more information about two-way binding, | |
385 plus examples of using it with a variety of | |
386 HTML5 widgets, check out | |
387 [Two-way data binding using Polymer](/docs/tutorials/forms/#binding-data). | |
Kathy Walrath
2013/10/11 16:36:03
When I followed this link, I was a bit disoriented
mem
2013/10/11 18:21:30
Done.
| |
383 | 388 |
384 You can use expressions within the double curly brackets. | 389 You can use expressions within the double curly brackets. |
385 <a href="http://pub.dartlang.org/packages/polymer_expressions" | 390 <a href="http://pub.dartlang.org/packages/polymer_expressions" |
386 target="_blank">Polymer expressions</a> | 391 target="_blank">Polymer expressions</a> |
387 provide the default syntax. Examples of allowable expressions include: | 392 provide the default syntax. Examples of allowable expressions include: |
388 | 393 |
389 |---|---| | 394 |---|---| |
390 | `{``{``myObject.aProperty}}` | Property access. | | 395 | `{``{``myObject.aProperty}}` | Property access. | |
391 | `{``{``!empty}}` | Operators, like the logical not operator. | | 396 | `{``{``!empty}}` | Operators, like the logical not operator. | |
392 | `{``{``myList[3]}}` | List indexing. | | 397 | `{``{``myList[3]}}` | List indexing. | |
(...skipping 19 matching lines...) Expand all Loading... | |
412 <a href="https://api.dartlang.org/dart_html/Event.html" target="_blank">Event</a > | 417 <a href="https://api.dartlang.org/dart_html/Event.html" target="_blank">Event</a > |
413 that contains information about the event, | 418 that contains information about the event, |
414 such as its type and when it occurred. | 419 such as its type and when it occurred. |
415 | 420 |
416 * The _detail_ object can provide additional, event-specific information. | 421 * The _detail_ object can provide additional, event-specific information. |
417 | 422 |
418 * The <a href="https://api.dartlang.org/dart_html/Node.html" target="_blank">Nod e</a> | 423 * The <a href="https://api.dartlang.org/dart_html/Node.html" target="_blank">Nod e</a> |
419 that fired the event—the **Start** button in this case. | 424 that fired the event—the **Start** button in this case. |
420 | 425 |
421 You can attach event handlers for other kinds of events. | 426 You can attach event handlers for other kinds of events. |
422 For example, you can use `on-change` to handle events for input text elements | 427 For example, you can use `on-input` to handle events |
423 when the text changes. | 428 for input text elements when the text changes. |
424 | 429 |
425 Refer to | 430 Refer to |
426 [Declarative event mapping](http://www.polymer-project.org/polymer.html#declarat ive-event-mapping) | 431 [Declarative event mapping](http://www.polymer-project.org/polymer.html#declarat ive-event-mapping) |
427 for further details. | 432 for further details. |
428 | 433 |
434 {% comment %} | |
429 ##Querying the shadow root {#in-the-shadows} | 435 ##Querying the shadow root {#in-the-shadows} |
430 | 436 |
431 The Shadow DOM is key to encapsulation. | 437 The Shadow DOM is key to encapsulation. |
432 The DOM subtree for a custom element is | 438 The DOM subtree for a custom element is |
433 hidden from outside of the custom element. | 439 hidden from outside of the custom element. |
434 | 440 |
435  | 441  |
436 | 442 |
437 You can programmatically get items from the Shadow DOM | 443 You can programmatically get items from the Shadow DOM |
438 by querying a custom element's _shadow root_—a | 444 by querying a custom element's _shadow root_—a |
439 special node from which an instance of a custom element is rendered. | 445 special node from which an instance of a custom element is rendered. |
440 | 446 |
441 {% prettify dart %} | 447 {% prettify dart %} |
442 startButton = getShadowRoot('tute-stopwatch').query('#startbutton'); | 448 startButton = getShadowRoot('tute-stopwatch').query('#startbutton'); |
443 stopButton = getShadowRoot('tute-stopwatch').query('#stopbutton'); | 449 stopButton = getShadowRoot('tute-stopwatch').query('#stopbutton'); |
444 resetButton = getShadowRoot('tute-stopwatch').query('#resetbutton'); | 450 resetButton = getShadowRoot('tute-stopwatch').query('#resetbutton'); |
445 {% endprettify %} | 451 {% endprettify %} |
446 | 452 |
447 Call `getShadowRoot()` with the name of the custom element. | 453 Call `getShadowRoot()` with the name of the custom element. |
448 The `getShadowRoot()` method returns the shadow root element | 454 The `getShadowRoot()` method returns the shadow root element |
449 for this instance of the specified element. | 455 for this instance of the specified element. |
450 Use `query()` with a CSS selector to get the element(s) of interest. | 456 Use `query()` with a CSS selector to get the element(s) of interest. |
451 | 457 |
452 Note that this code uses `query()` to get each button by ID. | 458 Note that this code uses `query()` to get each button by ID. |
453 By querying the shadow root object rather than the DOM, | 459 By querying the shadow root object rather than the DOM, |
454 you are guaranteed to get the objects from within the custom element, | 460 you are guaranteed to get the objects from within the custom element, |
455 not from anywhere else on the page. | 461 not from anywhere else on the page. |
462 {% endcomment %} | |
456 | 463 |
457 ##Styling a custom element {#scoped-css} | 464 ##Styling a custom element {#scoped-css} |
458 | 465 |
459 You can optionally include CSS styles for your custom element | 466 You can optionally include CSS styles for your custom element |
460 that apply only to the contents of the custom element. | 467 that apply only to the contents of the custom element. |
461 | 468 |
462  | 469  |
463 | 470 |
464 The `@host` rule allows you to target and style an element internally, | 471 The `@host` rule allows you to target and style an element internally, |
465 from within its definition. | 472 from within its definition. |
466 The `:scope` pseudo-class refers to the custom element itself. | 473 The `:scope` pseudo-class refers to the custom element itself. |
467 The only selectors that work in `@host` are those targeting the host element its elf. | 474 The only selectors that work within `@host` are those contained |
475 in the host element itself. | |
468 So you don't need to worry about naming conflicts on the page. | 476 So you don't need to worry about naming conflicts on the page. |
469 Any CSS selectors within the template need to be unique only within the template . | 477 Any CSS selectors within the template need to be unique only within the template . |
470 | 478 |
471 For further details about styling custom elements, | 479 For further details about styling custom elements, |
472 refer to | 480 refer to |
473 [A Guide to Styling Elements](http://www.polymer-project.org/articles/styling-el ements.html) | 481 [A Guide to Styling Elements](http://www.polymer-project.org/articles/styling-el ements.html) |
474 | 482 |
475 ##Other resources | 483 ##Other resources |
476 | 484 |
477 Use these other resources to learn more about Polymer: | 485 Use these other resources to learn more about Polymer: |
478 | 486 |
479 * The tutorial | 487 * The tutorial |
480 <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web" | 488 <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web" |
481 target="_blank">github repo</a> | 489 target="_blank">github repo</a> |
482 contains many examples that use Polymer, | 490 contains many examples that use Polymer, |
483 including samples that have been converted from Web UI. | 491 including samples that have been converted from Web UI. |
484 | 492 |
485 * The | 493 * The |
486 <a href="http://www.dartlang.org/polymer-dart/" | 494 <a href="http://www.dartlang.org/polymer-dart/" |
487 target="_blank">Polymer.dart</a> homepage provides information | 495 target="_blank">Polymer.dart</a> homepage provides information |
488 specific to the Dart port of the Polymer project. | 496 specific to the Dart port of the Polymer project. |
489 | 497 |
490 * The Polymer project website | 498 * The Polymer project website |
491 <a href="http://www.polymer-project.org/" | 499 <a href="http://www.polymer-project.org/" |
492 target="_blank">polymer-project.org</a> | 500 target="_blank">polymer-project.org</a> |
493 contains information about the Polymer project as a whole. | 501 contains information about the Polymer project as a whole. |
494 | 502 |
503 ##What next? | |
504 | |
505 [Two-way data binding with Polymer](/docs/tutorials/forms/#binding-data) | |
506 in the tutorial about forms shows how to use two-way data binding | |
Kathy Walrath
2013/10/11 16:36:03
ah, I see you gave the context here. (just do the
mem
2013/10/11 18:21:30
Done.
| |
507 with various types of input elements such as text fields, color pickers, | |
508 and so on. | |
509 | |
510 Check out these other tutorial examples that use Polymer. | |
Kathy Walrath
2013/10/11 16:36:03
. -> :
mem
2013/10/11 18:21:30
Done.
| |
511 | |
512 * <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/f etchdata/its_all_about_you" | |
513 target="_blank">its_all_about_you</a> | |
514 * <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/f orms/slambook" | |
515 target="_blank">slambook</a> | |
516 * <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/i ndexeddb/count_down" | |
517 target="_blank">count_down</a> | |
518 | |
519 The next tutorial, | |
520 [Fetch Data Dynamically](/docs/tutorials/fetchdata/), | |
521 shows you how to fetch data | |
522 and use JSON to encode and decode | |
523 that data. | |
524 | |
495 {% endcapture %} | 525 {% endcapture %} |
496 | 526 |
497 {% include tutorial.html %} | 527 {% include tutorial.html %} |
OLD | NEW |