Sunday, June 23, 2013

My First Web UI Component

‹prev | My Chain | next›

With my ICE Code Editor house more or less in order, I would like to take a day or two to explore web-ui in Dart. I have only glanced at a few of the article on it, which is enough make me curious, but not enough to really understand it.

I am interested in all that web-ui has to offer—the model-driven-views are of definite interest to me since they would seems a logical extension of the MVC application that serves as the basis for much of the narrative in Dart for Hipsters. But today, I am more curious about the component aspect of web-ui. Specifically, can I use them to build a custom HTML tag for ICE?

I will start with the Full Screen / IDE-lite version of ICE. It would be very cool indeed to have a custom x-ice-code-editor tag. Per the tool article, I need to start by installing the web-ui package from Dart Pub. This is Dart, so it's trivial. I add a web-ui entry in my pubspec.yaml:
name: ice_code_editor
version: 0.0.1
description: Code Editor + Preview
dependencies:
  web_ui: any
  js: ">=0.0.22 <0.0.23"
  crypto: ">=0.5.20 <0.5.21"
  unittest: ">=0.5.20 <0.5.21"
Then do a pub install:
➜  ice-code-editor git:(web-ui) ✗ pub install
Resolving dependencies...........
Downloading web_ui 0.4.12+2 from hosted...
Downloading logging 0.5.20 from hosted...
Downloading pathos 0.5.20 from hosted...
Downloading source_maps 0.5.20 from hosted...
Downloading csslib 0.4.7+6 from hosted...
Downloading args 0.5.20 from hosted...
Downloading analyzer_experimental 0.5.20 from hosted...
Dependencies installed!
I start my web-ui version of ICE in a web_ui.html file:
<html>
  <head>
    <script src="packages/browser/dart.js"></script>
    <script src="packages/browser/interop.js"></script>
  </head>
  <body>
  <x-ice-code-editor></x-ice-code-editor>
  <element name="x-ice-code-editor" extends="div">
    <template>
      {{ el }}
    </template>
    <script type="application/dart">
      import 'package:ice_code_editor/ice.dart' as ICE;
      import 'package:web_ui/web_ui.dart';

      class IceCodeEditor extends WebComponent {
        Full ide_lite;
        IceCodeEditor() {
          ide_lite = new ICE.Full();
        }
        get el => ide_lite.el;
      }
    </script>
  </element>
  </body>
</html>
I leave the dart.js and interop.js files to kick the dart engine and the js-interop stuff that ICE needs. The rest, I mostly copy from tutorials. I have a containing <element> tag that contains my component definition and sets the tag name to the desired <x-ice-code-editor>. I then add a template that inserts the element that is generated by the full-screen IDE class. I have the feeling that won't work as most values in the examples seem to be strings or other primitives. Still it is worth a shot. Then I create the element's constructor. The documentation suggests that the constructor can default to the camel-cased version of the tag, which I try.

I compile only to find:
➜  public git:(web-ui) ✗ dart --package-root=packages/ packages/web_ui/dwc.dart --out web_ui/ web_ui.html 
warning web_ui.html:1:1: Unexpected start tag (html). Expected DOCTYPE.
<html>
^^^^^^
warning web_ui.html:7:3: Implied constructor name for x-tags has changed to "XIceCodeEditor". You should rename your class or add a constructor="IceCodeEditor" attribute to the element declaration. Also custom tags are not required to start with "x-" if their name has at least one dash.
  <element name="x-ice-code-editor" extends="div">
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Looks like I need a doctype declaration in there—that's easy enough. It also seems that the default constructor has changed to include a leading “X”—that also seems easy enough. I fix those:
<!DOCTYPE html>
<html>
  <head>
    <script src="packages/browser/dart.js"></script>
    <script src="packages/browser/interop.js"></script>
  </head>
  <body>
  <x-ice-code-editor></x-ice-code-editor>
  <element name="x-ice-code-editor" extends="div">
    <template>
      {{ el }}
    </template>
    <script type="application/dart">
      import 'package:ice_code_editor/ice.dart' as ICE;
      import 'package:web_ui/web_ui.dart';

      class XIceCodeEditor extends WebComponent {
        Full ide_lite;
        XIceCodeEditor() {
          ide_lite = new ICE.Full();
        }
        get el => ide_lite.el;
      }
    </script>
  </element>
  </body>
</html>
And with that, I have a working component. It doesn't do much just yet, but it is a component.

I will remove the {{ el }} from the template, leaving it completely blank. As feared, that is only for inserting string-like values and is auto-converted to a string “div” and inserted at the top of the editor:



So in the end, my web component is little more than the simple Dart that normally defines ICE. It is still of some value for a more HTML-y way of instantiating an editor. Still, the main value lies in further developing the component for smaller components that can be inserted into a web page. That's something for another day.


Day #791

2 comments:

  1. Note that the 'x-' prefix isn't needed anymore. It is only required that the element name contains at least one '-' dash. In your case, that would be 'ice-code-editor'. That would correspond to the class name IceCodeEditor.

    ReplyDelete
    Replies
    1. Awesome tip, thanks! I was going to argue that I like the x- prefix as making it at-a-glance obvious that it is not a “real” tag, but then I realized that the dashes do that quite nicely, thank you very much. I'll switch it over now :)

      Delete