Two-way data binding with Web UI custom elements and models
Preface
This could very well be my last Web UI post! The Dart team announced they started on polymer.dart, a port of the Polymer project to Dart. Polymer.dart is the next evolution of Web UI. Luckily, the concepts are mostly the same and the syntax is mostly the same, because Web UI is also an implementation of the Web Components.
So why am I still writing about Web UI? Lots of people have asked about two-way data binding between a component and a model, so I wanted to have a record of this functionality. Also, what's described below isn't too different than how polymer.dart works (and we'll cover it in a future post).
I look forward to the glorious new world of coordinated polyfills and new custom elements. Go go polymer.dart and the Polymer project!
Intro
The Dart class that backs a custom element can itself also take part in two-way data binding. This post explores how to bind a model object to a web component property. If a model's field changes, the custom element's property changes. If the custom element's property changes, the model's field changes.
(Note: the same technique, with different syntax, should work in polymer.dart as well.)
The demo app contains:
Defining the ToggleComponent
Press the Toggle button (the custom component) and it runs toggle() which flips the ToggleComponent's internal state field. Because state is bound to lightSwitch.flipped, the switch is also flipped. Pretty cool!
Summary
You can bind a component's property to a model's field. This works today with Web UI's bind-foo attribute, and should work with polymer.dart's foo="{{model.field}}" attribute.
Meanwhile, Web UI is being phased out in favor of polymer.dart. Both libraries have the same goal: provide excellent implementations of modern and emerging web specifications and to help developers build amazing modular and beautiful web apps!
This could very well be my last Web UI post! The Dart team announced they started on polymer.dart, a port of the Polymer project to Dart. Polymer.dart is the next evolution of Web UI. Luckily, the concepts are mostly the same and the syntax is mostly the same, because Web UI is also an implementation of the Web Components.
So why am I still writing about Web UI? Lots of people have asked about two-way data binding between a component and a model, so I wanted to have a record of this functionality. Also, what's described below isn't too different than how polymer.dart works (and we'll cover it in a future post).
I look forward to the glorious new world of coordinated polyfills and new custom elements. Go go polymer.dart and the Polymer project!
Intro
The Dart class that backs a custom element can itself also take part in two-way data binding. This post explores how to bind a model object to a web component property. If a model's field changes, the custom element's property changes. If the custom element's property changes, the model's field changes.
(Note: the same technique, with different syntax, should work in polymer.dart as well.)
The demo app contains:
- A model for a Switch
- A custom element for a Toggle
The goal
When the switch is flipped, we want to flip the toggle. When the toggle is flipped, we want to flip the switch. Both Switch and Toggle don't know about each other. Let's connect them!
When the switch is flipped, we want to flip the toggle. When the toggle is flipped, we want to flip the switch. Both Switch and Toggle don't know about each other. Let's connect them!
Defining the Switch model
The Switch class is a standard business model, and it's marked as @observable.
library toggle;
import 'package:web_ui/web_ui.dart';
@observable
class Switch {
String flipped = 'off';
}
Defining the ToggleComponent
The Toggle custom element has two files: the <element> definition and the Dart class.
The Dart class for ToggleComponent is also @observable, and has a single field: state.
The custom component renders a button, and displays the state field. The button changes the state field by calling the toggle() method.
Initializing and controlling the switch
Inside the main app, create a single Switch instance and two methods that turn the switch on or off.
Connecting the Switch to the Toggle
Web UI supports two-way binding on custom elements with its bind-foo attribute, where foo is the name of a property on the custom element's backing class.
In this example, we bind toggle's state to switch's flipped field. This code comes from app.html:
Live demo
The Dart class for ToggleComponent is also @observable, and has a single field: state.
library turn_off;
import 'package:web_ui/web_ui.dart';
@observable
class ToggleComponent extends WebComponent {
String state = 'On';
void toggle() {
if (state == 'On') {
state = 'Off';
} else {
state = 'On';
}
}
}
The custom component renders a button, and displays the state field. The button changes the state field by calling the toggle() method.
<!DOCTYPE html>
<html>
<body>
<element name="toggle" constructor="ToggleComponent" extends="div">
<template>
<button on-click="toggle()">Toggle</button>
<p>Inside the component: The toggle is {{state}}</p>
</template>
<script type="application/dart" src="toggle_component.dart"></script>
</element>
</body>
</html>
Initializing and controlling the switch
Inside the main app, create a single Switch instance and two methods that turn the switch on or off.
library app;
import 'dart:html';
import 'package:web_ui/web_ui.dart';
import 'switch.dart';
Switch lightSwitch = new Switch();
turnSwitchOn() {
lightSwitch.flipped = 'On';
}
turnSwitchOff() {
lightSwitch.flipped = 'Off';
}
void main() {
}
Connecting the Switch to the Toggle
Web UI supports two-way binding on custom elements with its bind-foo attribute, where foo is the name of a property on the custom element's backing class.
In this example, we bind toggle's state to switch's flipped field. This code comes from app.html:
<div is="toggle" bind-state="lightSwitch.flipped"></div>
<p>The switch is set to {{lightSwitch.flipped}}</p>
<p>
<button on-click="turnSwitchOn()">Turn Switch On</button>
<button on-click="turnSwitchOff()">Turn Switch Off</button>
</p>
Live demo
Press the Toggle button (the custom component) and it runs toggle() which flips the ToggleComponent's internal state field. Because state is bound to lightSwitch.flipped, the switch is also flipped. Pretty cool!
Summary
You can bind a component's property to a model's field. This works today with Web UI's bind-foo attribute, and should work with polymer.dart's foo="{{model.field}}" attribute.
Meanwhile, Web UI is being phased out in favor of polymer.dart. Both libraries have the same goal: provide excellent implementations of modern and emerging web specifications and to help developers build amazing modular and beautiful web apps!