Get the code with git clone git://github.com/dzenanr/web_links.git
command. We start our discussion with the first spiral in the web_linksweb_links_s01
project.
In this spiral, we just show a web component that contains a list of links of the String
type, as shown in the following screenshot:
The webindex.html
start up HTML page imports the web component with:
<link rel="import" href="packages/web_links/links_app.html">
The component with the links-app
name is instantiated in the <body>
tag of the page:
<links-app></links-app>
The liblinks_app.html
file contains the UI definition of the component:
<link rel="import" href="../../packages/web_links/link_list.html"> <polymer-element name="links-app"> <template> <link-list></link-list> </template> <script type="application/dart" src="links_app.dart"></script> </polymer-element>
This in its turn imports a <link-list>
web component defined in link_list.html
:
<polymer-element name="link-list"> <template> (1) <ul> <template repeat="{{link in links}}"> (2) <li> <a href="{{link}}"> (3) {{link}} </a> </li> </template> </ul> </template> <script type="application/dart" src="link_list.dart"></script> (4) </polymer-element>
The outer template in line (1)
is required. The template in line (2)
uses a repeat
statement to iterate over the links
: repeat="{{link in links}}
list. The link
variable takes on the value of each list item in succession, and is shown through {{link }}
in the next line. The list is constructed in the link_list.dart
script referenced in line (4)
:
import 'package:polymer/polymer.dart'; @CustomTag('link-list') class LinkList extends PolymerElement { List links = ['http://ondart.me/', 'https://www.dartlang.org/polymer-dart/']; LinkList.created() : super.created(); }
Now, we will base the web component on a model with one simple concept: a web link. This has two attributes: a name
and a url
. The Link
class is defined in libmodellinks.dart
:
class Link { String name; Uri url; Link(this.name, String link) { url = Uri.parse(link); } }
It is a best practice to put our model in its own links
library in a separate lib
folder. The Polymer framework is based on the statement: everything is a component. We use a <links-app></links-app>
web component in index.html
that encapsulates the user interface and is also imported through a <link>
tag <link rel="import" href="packages/web_links/links_app.html">
. We show all our links as a <link-list>
component in links_app.html
, so the <link-list>
component is embedded in <links-app>
:
<link rel="import" href="../../packages/web_links/view/link_list.html"> <polymer-element name="links-app"> <template> <link-list links="{{links}}"></link-list> (1) </template> <script type="application/dart" src="links_app.dart"></script> </polymer-element>
This component in its turn is defined in viewlink_list.html
and viewlink_list.dart
.
In the links_app.dart
file, we find the code for the <links-app>
component that constructs a links collection called links
:
import 'package:web_links/web_links.dart'; import 'package:polymer/polymer.dart'; @CustomTag('links-app') class LinksApp extends PolymerElement { var links = toObservable(new List<Link>()); LinksApp.created() : super.created() { var link1 = new Link('On Dart', 'http://ondart.me/'), var link2 = new Link('Polymer.dart' 'https://www.dartlang.org/polymer-dart/'), var link3 = new Link('Books To Read', 'http://www.goodreads.com/'), links..add(link1)..add(link2)..add(link3); (2) } }
Our <links-app>
component is now instantiated through the template in line (1)
in the preceding code; it needs a links
variable, which is made in the LinksApp
constructor in line (2)
.
The web component in link_list.html
also uses the repeating template introduced in spiral s01, but now shows the names of the links:
<template repeat="{{link in links}}"> <li> <a href="{{link.url.toString()}}"> {{link.name}} </a> </li> </template>
The link_list.dart
file now also imports our model from the links
library and annotates the links
variable with @published
in line (3)
to show its contents:
import 'package:web_links/web_links.dart'; import 'package:polymer/polymer.dart'; @CustomTag('link-list') class LinkList extends PolymerElement { @published List<Link> links; (3) LinkList.created() : super.created(); }
When you run the preceding code, it will look like the following screenshot:
Apart from some added style in spiral s03, the <links-app>
component is identical to the one in spiral s02.
In this spiral, we will also provide the possibility to add a web link by the user:
A new link has to be shown; in order to accomplish this, we have to mark the list with toObservable
in the links_app.dart
file:
var links = toObservable(new List<Link>());
The definition of the web links component in the link_list.html
file now contains additional UI markup in its <template>
tag to enable us to add links:
<div> <label for="name">Name</label> <input id="name" type="text"/> <label for="url">web Link</label> <input id="url" type="text"/><br/> <button on-click="{{add}}" class="button">Add</button> (1) <label id="message"></label> </div> <ul> <!-- repeating template --> </ul></template> <script type="application/dart" src="link_list.dart"></script>
The add
method from line (1)
is found in the link_list.dart
script:
add(Event e, var detail, Node target) { (2) InputElement name = shadowRoot.querySelector("#name"); (3) InputElement url = shadowRoot.querySelector ("#url"); LabelElement message = shadowRoot.querySelector ("#message"); var error = false; message.text = ''; if (name.value.trim() == '') { message.text = 'name is mandatory; ${message.text}'; error = true; } if (url.value.trim() == '') { message.text = 'web link is mandatory; ${message.text}'; error = true; } if (!error) { var weblink = new Link(name.value, url.value); weblinks.add(weblink); (4) } }
Notice how in line (1)
the add
event handler is called in {{ }}
. In line (2)
, we can see that it has three arguments: the third one is a direct reference to the target element on which the event happened. In line (3)
and the ones that follow, we see how to get a reference to the inner markup of a web component. The familiar querySelector
method call is now preceded by shadowRoot
:
shadowRoot.querySelector("#name");
In spiral s05, we add the functionality to store our web links in the local storage by adding the code needed to load and save data to the model. The save functionality is implemented in the link_list.dart
script of the <link-list>
component. In the preceding code, after line (4)
, we will now add:
if (!error) { // previous code save(); }
We will then add this save method:
save() { window.localStorage['web_links'] = JSON.encode(toJson()); }
We want to save our data in the JSON format. To do this, our Link
model class needs to know how to transform itself in a Map (with a toJson
method) or to construct itself from a Map (using the Link.fromJson
constructor):
Map<String, Object> toJson() { var linkMap = new Map<String, Object>(); linkMap['name'] = name; linkMap['url'] = url.toString(); return linkMap; } Link.fromJson(Map<String, Object> linkMap) { name = linkMap['name']; url = Uri.parse(linkMap['url']); }
The constructor LinksApp()
method in links_app.dart
first creates a list in line (4)
, and then calls the load()
method in line (5)
to read the data from the local storage:
var links = toObservable(new List<Link>()); (4) LinksApp.created() : super.created() { load(); (5) } load() { String json = window.localStorage['web_links']; if (json == null) { init(); (6) } else { fromJson(JSON.decode(json)); (7) } }
If nothing was stored yet, the Model
object is initialized via the init()
method in line (6)
, otherwise, it is parsed from local storage in line (7)
. In line (4)
, the List
object of links is created. As there is only one model
object, we can safely refer to the unique links object of model
to feed links within the web component's Dart code.
In spiral s06, the possibility is added to remove links, as shown in the following screenshot:
To allow this, a second button is placed inside the <template>
tag of the <link-list>
component:
<button on-click="{{delete}}" class="button">Remove</button>
The delete
method is implemented in the script of the link_list.dart
component:
delete(Event e, var detail, Node target) { InputElement name = shadowRoot.querySelector("#name"); InputElement url = shadowRoot.querySelector ("#url"); LabelElement message = shadowRoot.querySelector("#message"); message.text = ''; Link link = links.find(name.value); if (link == null) { message.text = 'web link with this name does not exist'; } else { url.value = link.url.toString(); if (links.remove(link)) save(); } }
3.142.199.181