在 Polymer 中重置表单 2.x

Resetting forms in Polymer 2.x

我正在尝试重置我的表格。我究竟做错了什么?什么是最佳实践?

Here is my Plunk demo.

我在演示中遇到的问题是 connectedCallback() 似乎持续触发(不仅仅是在初始加载时),因此通过将 savedItem 更新为 newItem 来丢失 savedItem 的值更新。

Here is the same issue on Github.

https://plnkr.co/edit/wRdXXws2UXl3VXrycqua?p=preview

我的-demo.html
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer-element.html">
<link rel="import" href="paper-toggle-button/paper-toggle-button.html">


<dom-module id="my-demo">
  <template>
    <style>
      :host > * {
        margin-top: 40px;
        font-size: 18px;
      }
      button.save {
        color: white;
        background-color: blue;
      }
    </style>

    <paper-toggle-button checked="{{item.alice}}">Alice</paper-toggle-button>
    <paper-toggle-button checked="{{item.bob}}">Bob</paper-toggle-button>
    <paper-toggle-button checked="{{item.charlie}}">Charlie</paper-toggle-button>
    <paper-toggle-button checked="{{item.dave}}">Dave</paper-toggle-button>

    <button>Reset</button>
    <button class="save" on-tap="_reset">Save</button>

  </template>

  <script>
    class MyDemo extends Polymer.Element {
      static get is() {
        return 'my-demo';
      }
      static get properties() {
        return {
          item: {
            type: Object,
            notify: true,
            value: () => {
              return {
                alice: false,
                bob: false,
                charlie: false,
                dave: true,
              };
            },
          },
          savedItem: {
            type: Object,
            notify: true,
          },
        };
      }

      connectedCallback() {
        super.connectedCallback();
        this.set('savedItem', this.item);
      }

      static get observers() {
        return [
          '_itemChanged(item.*)',
        ];
      }

      _itemChanged(newItem) {
        console.log('saved-item', this.savedItem);
        console.log('new-item', newItem);
      }

      _reset() {
        this.set('item', this.savedItem);
      }

    }

    window.customElements.define(MyDemo.is, MyDemo);
  </script>
</dom-module>

编辑

重现问题的步骤

  1. Open the demo here.

  2. 打开控制台。

  3. 在 Plunker 中导航到我的-demo.html

  4. 单击其中一个切换开关。

  5. 控制台通知,savedItem属性更新为当前item属性.

  6. 注意,这似乎是以下代码块的结果。

      connectedCallback() {
        super.connectedCallback();
        this.set('savedItem', this.item);
      }
    

但这怎么可能呢?因为我认为 connectedCallback() 只在初始化时触发一次?

tldr; 在这种情况下,connectedCallback() 实际上并没有被多次调用。 savedItemitem 在您的代码中始终是同一个对象,因为 JavaScript 传递对象 by reference.


对象引用

在下面:

connectedCallback() {
  this.set('savedItem', this.item);
}

_reset() {
  this.set('item', this.savedItem);
}

savedItemitem 都是对同一对象的引用。调用 this.set() 不会自动克隆操作数(= 运算符也不会)。

一个解决方案是在赋值前克隆对象(使用ES2017 object-spread operator):

connectedCallback() {
  this.savedItem = {...this.item};
}

_reset() {
  this.item = {...this.savedItem};
}

updated plunker


最佳实践(或更简单的重置方法)

重置表单的更简单方法是让 iron-form 处理表单的 reset 事件,它将表单的命名输入重置为其初始值。这使您不必声明 savedItem 并且不需要额外的 JavaScript 来管理它。

为此,将 <paper-toggle-button> 包装在 <iron-form> 中,并向其添加 name 属性。然后,在表单中插入一个<input type="reset">,作为重置按钮。

<iron-form>
  <form>
    <paper-toggle-button name="alice" checked="{{item.alice}}">Alice</paper-toggle-button>
    <paper-toggle-button name="bob" checked="{{item.bob}}">Bob</paper-toggle-button>
    <paper-toggle-button name="charlie" checked="{{item.charlie}}">Charlie</paper-toggle-button>
    <paper-toggle-button name="dave" checked="{{item.dave}}">Dave</paper-toggle-button>

    <input type="reset" class="save">
  </form>
</iron-form>

demo