domingo, 17 de noviembre de 2013

Let's use objects in our Web Components

In our basic example we have 2 attributes, but what happens when we create a more complex web component that can potentially have tens of attributes? Writing down all of them one by one is not optimum, but one of the good things of web components is that we can use objects to encapsulate all this inifo just as we do with a normal Dart or Java program. The first step is to create a model.dart file in which we will define our object:

library models;

import 'package:polymer/polymer.dart';

class Icon extends Object with Observable {
  @observable String name;
  @observable String imageUrl;

  Icon({this.name: "Icon", this.imageUrl: "http://www.erlantzoniga.com/images/folder.png"});
}

It's basically the same as a normaal object you would use in a Dart program with a single difference, the @observable annotation before the variables. This annotation binds the variable to the web component, so if we update the variable name the web component will be update with the new value and if the web component modifies it's value (in an input box for example) the variable value will also be updated.

Now that we have the Icon class created let's update our previous code. First of all let's update icon.dart and icon.html:

import 'model.dart';
import 'package:polymer/polymer.dart';

@CustomTag('x-icon')
class IconElement extends PolymerElement {
  @published Icon icon = new Icon();

  IconElement.created() : super.created() {
  }
}

<polymer-element name="x-icon" attributes="icon">
  <template>
    <style>
      div {
        font-size: 10pt;
        text-align: center;
        margin: 10px;
        width: 100px;
        display: inline-block;
      }
      img {
        width: 90px;
        height: 90px;
        padding: 5px;
      }
    </style>
    <div>
      <img src="{{icon.imageUrl}}" alt="{{icon.name}}" />
      <span>{{icon.name}}</span>
    </div>
  </template>
  <script type="application/dart" src="icon.dart"></script>
</polymer-element>

In Icon.dart we have replaced our previous attributes with an object of our new class Icon. In Icon.html we have changed the attributes declaration in the top too and have updated the references inside the component form the previous variable names to the icon object's attributes. Now let's update icon-panel.dart and icon-panel.html to use our new Icon class and the updated icon.dart and icon.html:
import 'model.dart';
import 'package:polymer/polymer.dart';

@CustomTag('x-icon-panel')
class IconPanelElement extends PolymerElement {
  List<Icon> icons = new List<Icon>();

  IconPanelElement.created() : super.created() {
    for (int i = 0; i < 10; i++) {
      icons.add(new Icon(name: "Icon ${i +1}"));
    }
  }
}

<link rel="import" href="icon.html">
<polymer-element name="x-icon-panel">
  <template>
    <style>
      div {
        font-size: 10pt;
        margin: 10px;
        width: 500px;
        height: auto;
        border: 1px solid black;
      }
    </style>
    <div id="icon-panel">
      <template repeat="{{icon in icons}}">
        <x-icon icon="{{icon}}"></x-icon>
      </template>
    </div>
  </template>
  <script type="application/dart" src="icon_panel.dart"></script>
</polymer-element>

In icon_panel.dart we replace the String List for a List of Icon and in the for loop we create new Icon objects with the default image and a custom name. In icon_panel.html we remove our conditionals because now we can't pass custom name or imageUrl because we have removed that attributes from our web component and instead we iterate a <x-icon> element passing the icon object as an attribute. Yes we are passing an object as an attribute in html, it's not magic it's the power of web components.

In the next tutorial we'll learn how to add events to our web components.