Polymer 1.0: Two-way bindings with input elements

Andre Gregori picture Andre Gregori · Jun 15, 2015 · Viewed 12.1k times · Source

Code

Consider the following Polymer custom element:

<dom-module id="test-element">

<template>
    <input type="text" value="{{value}}">
    <button>Reset</button>
</template>

<script>
Polymer({
    is: 'test-element',
    properties: {
        'value': {
            type: String,
            reflectToAttribute: true,
            notify: true,
            value: null
        }
    }
});
</script>

</dom-module>

I use this custom element in my index.html as follows:

<html>
<head>
    <script type="text/javascript" src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
    <link rel="import" href="test-element.html">
    <title>Test App</title>
</head>
<body>
    <test-element value="test"></test-element>
</body>
</html>

Question

I believe I have declared the value property as a two-way binding (notify: true); yet when I click on the input and type in some text (say, "foo"), it is not reflected in the model (i.e. a call to document.querySelector('test-element').value returns the value I set in index.html, "test"). Interestingly enough, the value attribute of the input changes correctly, but the value property of my test-element does not. What am I missing?

I should also note that a call to document.querySelector('test-element').setAttribute('value', 'bar') works properly.

Answer

Scott Miles picture Scott Miles · Jun 15, 2015

First note that the notify and reflectToAttribute fields on the value property tell it how to react to it's parent not about how to bind to a child.

IOW, notify: true means to make value two-way bindable from the outside, not from the inside. reflectToAttribute: true tells Polymer to write value to an attribute every time it changes (not good for performance).

When you do a binding like <x-element foo="{{value}}">, it's x-element that decides if foo is two-way bindable.

Native elements like input do not have two-way binding support built in, instead use Polymer's event-observer syntax to two-way bind to an input. Like so <input value="{{value::change}}">.

This tells Polymer to update this.value from input.value whenever the input fires a change event.