Polymer Data-Binding Filters

Web ComponentsOne useful feature of modern Javascript libraries is 2-way data-binding. All interactive websites perform this functionality one way or another, but only a few libraries such as Ember.js, AngularJS and Polymer don’t require a single line of Javascript.

2-way data-binding is the ability to keep two data sources in sync: if either changes the other will be automatically updated with the same value. More complicated use cases involve conditional statements or formula to define the relationship of the first and second values. Polymer Filters allow bi-directional binding even in these scenarios.

The code in this post references Polymer 0.1.3, and may change in subsequent releases.
Polymer only works with recent browsers, if you can’t see the demos update your browser.


One example would be to have 2 numbers which are a multiple of each other:

But not everyone is writing a spreadsheet application. Filters can also be used to perform arbitrary transformations; including text transformations.

<input type="text" value="{{simpleBind}}">
<input type="text" value="{{simpleBind}}">

Polymer allows rudimentary logic to be performed within bind {{expressions}}; although only a subset of Javascript is allowed, and 2-way binding is disabled. If we wanted to use expressions to append hi! to the end of input 2’s value, it would disable its ability to be used to update input 1.

<input type="text" value="{{expressionBind}}">
<input type="text" value="{{!expressionBind ? '' : expressionBind+', hi!'}}">

To retain 2-way binding we need a way to specify how to undo our binding expression. This ability is handled by a feature called Filters. They allow both the forward (Model-to-Dom) and reverse (Dom-to-Model) functions to be specified, using any valid Javascript.

If 2-way binding isn’t required, the toDom definition can be omitted. Filters can be also used instead of {{expressions}} when logic is too complex for the restricted set of operators {{expressions}} are limited to.

String.prototype.endsWith = function(suffix) {
  return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
PolymerExpressions.prototype.myCustomFilter = function(value) {
  if(!value){
    return '';
  }else{
    return value + ', hi!';
  }
};
PolymerExpressions.prototype.myCustomFilter.toModel = function(value) {
  if(!value){
    return '';
  }else if(value.endsWith(', hi!')){
    return value.substring(0,value.length-5);
  }else{
    return value;
  }
};    
<input type="text" value="{{filterBind}}">
<input type="text" value="{{filterBind | myCustomFilter}}">

Filters can also take additional arguments, any number of {{expression}} can be used. In the above example, we don’t need to hard-code the hi!, it could come from another input.

PolymerExpressions.prototype.myCustomFilter = function(value, a) {
  if(!value){
    return '';
  }else{
    return value + ', ' + a;
  }
};
PolymerExpressions.prototype.myCustomFilter.toModel = function(value, a) {
  if(!value){
    return '';
  }else if(value.endsWith(', ' + a)){
    return value.substring(0,value.length-2-a.length);
  }else{
    return value;
  }
};
<input type="text" value="{{arg}}"/>
<input type="text" value="{{filterBind}}">
<input type="text" value="{{filterBind | myCustomFilter(arg)}}">

Filters are a very concise way to perform data transformations without manually writing code or adding additional fields to the Web Component’s model. Polymer has a declarative style, and the use of filters for data manipulation further expand the idea allowing clear declaration of intent.

One thought on “Polymer Data-Binding Filters

  1. This doesn’t seem to work with input value fields. The initial binding works well, but once you start editing the field polymer loses scope of your filter resulting in undefined bindings. Useful for disabled/un-editable fields but, I can’t find a way around the input value filters.

    Check it out on JSBin: http://jsbin.com/hatusivijo/1/edit

    The initial binding in the case will revert anything the user types back to “tests”. Which works fine at startup, but once you start editing, as you can see in console the filter becomes undefined.

    Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

Help stop spam, fill out this captch: * Time limit is exhausted. Please reload CAPTCHA.