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.

domingo, 10 de noviembre de 2013

Using loops and conditionals in Web Components

Following with the icon web component example, we are going to create a simple panel that automatically spawns as many icons as objects we have in a list. First of all we are going to create the icon_panel.dart file with the following code:

import 'package:polymer/polymer.dart';

@CustomTag('x-icon-panel')
class IconPanelElement extends PolymerElement {
  List iconNames = new List();

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

As we can see it's a pretty basic object that only has a List of strings which we populate in its constructor. We use a List of strings to make it easier but we could use a Icon object and have each icon with its own image and name, but  we will see that in a future post. Now let's write our html template:

<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>
      <template repeat="{{name in iconNames}}">
        <template if="{{name == 'Icon 9'}}">
          <x-icon imageurl="https://lh5.googleusercontent.com/-6LE2zGf0peU/AAAAAAAAAAI/AAAAAAAAAe0/3lMdEfAJGCw/photo.jpg" filename="I'm the last one"></x-icon>
        </template>
        <template if="{{name != 'Icon 9'}}">
          <x-icon filename="{{name}}"></x-icon>
        </template>
      </template>
    </div>
  </template>
  <script type="application/dart" src="icon_panel.dart"></script>
</polymer-element>

This is a bit different from the  last time, but it's not very difficult to understand. In the first line we import the icon web component from our first example and then in our template we create a div (we are creating a panel after all) and this is where it gets trickier. We use a template tag with the attribute repeat to create a loop (it's basically like a for each loop) that  tells the web component to create the inside part  as many times as elements has the iconNames list. And for each iteration of the loop we get the item of the list that corresponds to that iteration on the variable names 'name'. In the inside of this template tag we have another 2 template tags with the 'if' attribute, this is for applying conditionals in web components, in this case we can see that if the name is 'Icon 9' it will create a x-icon element with an specific image and name, while if the name is different from 'Icon 9' it will create a x-icon element with the value of name variable as the filename and the default image.

Now let's modify our test.html file to use our new web component:

<html>
  <head>
    
    <title>Sample web component</title>
    <!-- import the icon panel component -->
    <link href="icon_panel.html" rel="import"></link>
    <script type="application/dart">export 'package:polymer/init.dart';</script>
    <script src="packages/browser/dart.js"></script>
  </head>
  <body>
    <h1>Icon panel component example</h1>
    <x-icon-panel></x-icon-panel>
  </body>
</html>

There is nothing new here except that with the last version of the SDK instead of importing package:polymer/init.dart we have to export it. Now let's see the result of our work:


jueves, 7 de noviembre de 2013

JSON vs YAML

The other day I was thinking of creating a config file for one of my projects because it's getting bigger  and controlling with IFs the values of some variables depending if the server is being executed in the production machine or my development laptop was supposed to be just a temporary patch that has been there too much time. So I searched on pub for a package that could load config files and I reached to dart_config.

When I was reading the documentation  I learned that it supported 2 different formats for loading the configuration, JSON and YAML, and I asked myself (and my friends) which will be a better option. I personally like more using curly braces like in JSON but YAML has somre pretty badass features too so I just decided to use the most efficient one. We thought the most efficient one would be JSON because it seems easier to parse but we weren't completely sure so one of my friends thought that making a little benchmark would be a good idea, so I did.

I created a simple yaml file, then I created a json file from it and after that I created another json file compressing the previous one (taking of all the whitespaces and line breaks). And I created the following code:

import 'dart:convert';
import 'dart:io';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:yaml/yaml.dart' as YAML;

void main() {
  YamlBenchmark.main();
  JsonBenchmark.main();
  CompressedJsonBenchmark.main();
}


class YamlBenchmark extends BenchmarkBase {
  const YamlBenchmark() : super("YAML");

  final String text = new File("./test.yaml").readAsStringSync();

  static void main() {
    new YamlBenchmark().report();
  }

  void run() {
    YAML.loadYaml(text);
  }
}

class JsonBenchmark extends BenchmarkBase {
  const JsonBenchmark() : super("JSON");

  final String text = new File("./test.json").readAsStringSync();

  static void main() {
    new JsonBenchmark().report();
  }

  void run() {
    JSON.decode(text);
  }
}

class CompressedJsonBenchmark extends BenchmarkBase {
  const CompressedJsonBenchmark() : super("Compressed JSON");

  final String text = new File("./compressedTest.json").readAsStringSync();

  static void main() {
    new CompressedJsonBenchmark().report();
  }

  void run() {
    JSON.decode(text);
  }
}


And the results of this benchmark had JSON as a clear winner:
YAML(RunTime): 5755.747126436781 us.
JSON(RunTime): 29.408737335862483 us.
Compressed JSON(RunTime): 24.88459767826704 us.

But then I realized that making the tests like this I made dissapear one of YAML's advantage against not compressed JSON, a smaller file that would take less time to read. So I decided to change the benchmark so the File is read each time and the time it takes to read it is part of the result.

import 'dart:convert';
import 'dart:io';
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:yaml/yaml.dart' as YAML;

void main() {
  YamlBenchmark.main();
  JsonBenchmark.main();
  CompressedJsonBenchmark.main();
}

class YamlBenchmark extends BenchmarkBase {
  const YamlBenchmark() : super("YAML");

  static void main() {
    new YamlBenchmark().report();
  }

  void run() {
    String text = new File("./test.yaml").readAsStringSync();
    YAML.loadYaml(text);
  }
}

class JsonBenchmark extends BenchmarkBase {
  const JsonBenchmark() : super("JSON");

  static void main() {
    new JsonBenchmark().report();
  }

  void run() {
    String text = new File("./test.json").readAsStringSync();
    JSON.decode(text);
  }
}

class CompressedJsonBenchmark extends BenchmarkBase {
  const CompressedJsonBenchmark() : super("Compressed JSON");

  static void main() {
    new CompressedJsonBenchmark().report();
  }

  void run() {
    String text = new File("./compressedTest.json").readAsStringSync();
    JSON.decode(text);
  }
}

And here are the results with the modified code:
YAML(RunTime): 6766.891891891892 us.
JSON(RunTime): 240.87679152113694 us.
Compressed JSON(RunTime): 206.1218179944347 us.

The winner continues being JSON but what before was 198x faster is now just 28x faster, althought the absolute time has increased more with the YAML file than with the JSON. We can also see the compressed JSON being (obviously) less affected by having to read the file. Probably with very big files we would see a smaller difference between YAML and JSON and bigger between compressed and uncompressed but that is a test for another day, because my config files won't bee too big and with small files we have a clear winner: JSON.

miércoles, 6 de noviembre de 2013

Dart 1.0 is almost here


The Dart team announced that since version 0.8.10+6 there won't be more breaking changes, so it's time to update our packages to version 1.0. Seth Ladd has made a faq in Google+ with the changes we developers have to do to prepare the packages we have in pub for version 1.0 like not using any in the pubspec.yaml anymore.

domingo, 3 de noviembre de 2013

How to create your first web-component with Dart

UPDATE: Updated test.html to be compatible with the last SDK (and with the future 1.0 version)

In my first post we will learn how to create a simple web-component with polymer.dart. First of all we have to create a new application in the Dart Editor:


Now we will have the default polymer.dart project which consists of a clickcounter component and the main html that loads the web-component. We will change the clickcounter files name for icon.dart and icon.html and update the code in both files.

<polymer-element attributes="imageUrl fileName" name="x-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 alt="{{fileName}}" src="{{imageUrl}}" />
      {{fileName}}
    </div>
  </template>
  <script src="icon.dart" type="application/dart"></script>
</polymer-element>

Our icon component is very simple it's just an image and a span with its filename inside a div. We use {{}} for using values of the web component's objects, in this case we use just attributes but our component could have an object of type Icon which had a imageUrl and filename attributes along with other attributes or methods. But we will let that for the next time, for now let just focus on creating a web component as simple as possible.

import 'package:polymer/polymer.dart';

/**
 * A Polymer click counter element.
 */
@CustomTag('x-icon')
class IconElement extends PolymerElement {
  @published String fileName = "Icon";
  @published String imageUrl = "http://erlantzoniga.com/images/folder.png";

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

In the dart file we cannThe first thing that catch's our eye when opening the dart file are the annotations. First of all we have the @CustomTag annotation that indicates to which polymer element belongs this code. The other annotation we see is @published before the declaration of the variables, this means that these variables are attributes of the component which means that we will be able to use:
<x-icon filename="Test" imageurl="http://www.example.com/image.jpg"></x-icon>
No we will update the main html to use our new web component. The name of the html is the same name of the project but we can call it as we like so I'm gonna call it test.html
<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <title>Sample web component</title>
    <!-- import the icon component -->
    <link rel="import" href="icon.html">
    <script type="application/dart">export 'package:polymer/init.dart';</script>
    <script src="packages/browser/dart.js"></script>
  </head>
  <body>
    <h1>Icon component example</h1>
    <!-- Default icon -->
    <x-icon></x-icon>
    <!-- Custom icon -->
    <x-icon imageurl="https://lh5.googleusercontent.com/-6LE2zGf0peU/AAAAAAAAAAI/AAAAAAAAAe0/3lMdEfAJGCw/photo.jpg" filename="Hello world!"></x-icon>
  </body>
</html>
The most important part here is the little dart code that imports init.dart without it the web component won't work. Using our new component it's as easy as using any standard html element as you can see and if we don't pass any attributes it will use the default ones.

And here is the end result:
Not bad for a first (and simple) web component. In the next post we'll learn how to iterate elements so we can create multiple icons in a row without having to manually write each tag.