Polymer 3:如何为无线电输入实现双向数据绑定

Polymer 3: How to implement two way data binding for radio input

我正在尝试 understand/implement 在 Polymer 3 Web 组件中进行两种方式的属性绑定。我有以下代码:

import {html, PolymerElement} from '@polymer/polymer/polymer-element.js';

 class CustomInputComponent extends PolymerElement {
    static get template() {
        return html`        
        <div>
            <template is="dom-repeat" items="{{ratings}}">
                <input type="radio" 
                       name="group" 
                       id="item_{{item.id}}" 
                       value="{{item.checked}}" 
                       checked$="{{item.checked}}">                
            </template>
        </div>`;
    }

    static get properties() {
        return {
            ratings: {
                type: Array,
                value: [
                    { id: 1, checked: true },
                    { id: 2, checked: false }
                ]
            }
        };
    }
}
window.customElements.define('custom-input-component', CustomInputComponent);

如您所见,我定义了一个包含默认值列表的数组 属性。这个 属性 是我要从中渲染单选组的模型。初始状态看起来不错。但是当我点击未选中的输入时,DOM 元素没有正确更新。

我敢打赌我错过了一些非常简单的东西...

主要有:

  • 您正在绑定到 checked 属性 ($=),但我认为无线电输入不会动态更新其 checked 属性。 AFAICT,checked 属性 是选择输入时发生的变化。

  • 此外,原生 <input type="radio"> 输入只会在它们被选中时触发它们的 changeinput 事件,而不是在它们被取消选择时。 Polymer 依靠事件来触发 属性 数据绑定等效果;这意味着只有当输入上的 checked 属性 从 false 变为 true 时,才会处理向上的数据绑定(从输入到您的自定义元素)。实际上,一旦 ratings[n].checked 变为真,它就永远不会变为假,因为 Polymer 无法知道这已经发生。

    顺便说一下,要对原生 HTML 元素执行双向绑定,you would also need to include an annotation for the event that the radio input fires when it is selected。所以如果你确实想捕捉选择的变化,它会像 checked="{{item.checked::change}}".

几个选项:

  • 使用 paper-radio-buttons inside a paper-radio-group 而不是原生的 <input>。这些元素对于双向数据绑定表现良好。

  • 选中新项目时监听变化,并手动更新ratings[n].checkedfalse之前选择的项目。

关于您的代码的更多信息

  • (我不认为这与您当前的问题有任何关系,但它有助于避免将来的问题)在初始化对象或数组的默认值时 属性一个 Polymer 元素,remember to use a function 这样每个元素实例都有自己唯一的数组或对象。例如:

    ratings: { type: Array, value: function(){ return [ { id: 1, checked: true }, { id: 2, checked: false } ]; } }

  • 通常我认为,您不会想要更改无线电输入的。按照惯例,当提交包含单选输入组的 <form> 时,当前为 checked 的单选输入上的 value 将包含在表单数据中,而忽略其他单选输入值. Here's an example on W3Schools。所以不是 value="{{item.checked}}",而是 value="[[item.data]]"

所以整个事情可能类似于

class CustomInputComponent extends PolymerElement {
  static get properties () {
    return {
      ratings: {
        type: Array,
        value: function(){ 
          return [
          { id: 1, checked: true, value: 'pie' },
          { id: 2, checked: false, value: 'fries' },
          { id: 3, checked: false, value: 'los dos' }
          ];
        }
      },
      selected: {
        // type: Number or Object, idk
        // Keep track of the selected <input>
      }
    };
  }
  static get template() {
    return html`        
      <p>do you want pie or fries?</p>
      <div id="mydiv">
        <template is="dom-repeat" items="{{ratings}}">
          <input 
            type="radio"
            name="testgroup"
            id="[[item.id]]"
            value="[[item.value]]"
            checked="{{item.checked::input}}"
            on-change="radioChanged"
            >[[item.value]]
          </input>
        </template>
      </div>
    `;
  }
  radioChanged(event){
    // update ratings[n].checked for selected input
    // set selected input to currently selected input
  }
}