Polymer 1.0: Two-way bindings with input elements

12.6k views Asked by At

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.

3

There are 3 answers

4
Scott Miles On BEST ANSWER

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.

1
Andrey On

You need to change this:

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

into

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

try here. This says for polymer to listen to input's events. Explained here (not very clearly IMO).

0
Steven Spungin On

As mentioned by Andrey and Scott Miles, both of these solutions will work to get 2-way-bind with a native HTML input box.

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

<input type="text" value="{{value::change}}">

With an important difference:

::change will only fire when the text box loses focus or enter is pressed.

::input will fire on every keypress.