In Polymer 2.0 how to observe edits to properties of an object bound to an element inside dom-repeat?

孤街醉人 提交于 2020-01-02 09:19:10

问题


(This question and code sample is for Polymer 2, but it's possible the same issue is present in 1.x)

The Goal:

I want to create an element (the Editor) that allows viewing/editing of the properties of certain types of objects, and another element (the List) that displays editable arrays of these objects, delegating the viewing/editing to the Editor element, while retaining control over the addition/removal of obejcts from the list. A to-do list is a good example of this (note: the Polymer to-do list examples floating around out there, as far as I'm aware, do not do what I need, read on to see why). I am trying to do this in Polymer 2.0, but it's not clear that the issue is specific to 2.0.

The Obstacle:

First, here's a bit of code on plunker:

https://plnkr.co/edit/Yji9kl63sOdnHJiv4CCU

The List element:

<link rel="import" href="./editor-element.html">

<dom-module id="list-element">
    <template>
        <dom-repeat items="{{list}}" as="item">
            <template>
                <div class="item">
                    <editor-element todo="{{item}}">
                    </editor-element>
                </div>
            </template>
        </dom-repeat>

    </template>
    <script>

        class ListElement extends Polymer.Element {

            static get is() {
                return "list-element";
            }

            static get properties() {
                return {
                    list: {
                        type: Array,
                        value:function() {
                            return []
                        }
                    }
                }
            }

            ready() {
                super.ready();
                this.push("list", {
                    description:"one"
                })
                this.push("list", {
                    description:"two"
                })
                setTimeout(function() {
                    this.set("list.0.description", "one edited");
                }.bind(this), 500)
                setTimeout(function() {
                    this.push("list", {
                        description:"three"
                    })
                }.bind(this), 1000)
            }
        }

        customElements.define(ListElement.is, ListElement);

    </script>
</dom-module>

The Editor element:

<dom-module id="editor-element">
    <template>
        <div>Editor for [[todo.description]]</div>
    </template>
    <script>

        class EditorElement extends Polymer.Element {

            static get is() {
                return "editor-element";
            }

            static get properties() {
                return {
                    todo:{
                        type:Object,
                        value:function() {
                            return {};
                        }
                    }
                }
            }

            static get observers() {
                return [
                    "observe(todo.description)"
                ]
            }

            observe(p1) {
                console.log("Observed change for TODO item description: "+p1);
            }
        }

        customElements.define(EditorElement.is, EditorElement);

    </script>
</dom-module>

The problem is that the observer in the Editor that is supposed to watch for edits to a to-do item is being fired when a new to-do item is created, in addition to when an existing to-do item is edited. This is happening BOTH for the new to-do item and for existing to-do items that have not been edited. In other words, if I have item A and B already on the list, and I add item C, the to-do property observer in the Editor is fired three times, one for each new/existing item. This happens regardless of whether the new item is pushed or unshifted onto/into the list. I understand from discussion on the Polymer 2 slack channel that the unshift behaviour is to be expected, but the push behaviour is unexpected.

The Question:

What is the Polymer Way (2.0 preferably) to achieve this use case? I do not want to pollute the List element with code to handle edits to a to-do item. The to-do items themselves are objects that may gain more properties in the future, so I don't want to individually bind each property of the dom-repeated item to a property in the Editor element, because this is a code maintenance nuisance. I want to just bind the entire to-do item in each pass of dom-repeat, and allow the Editor to deal with which properties are editable and how.

The answer to my question may be "Polymer can't do this" or it may be "You are misunderstanding something fundamental about Polymer", either or both of which I would love to know, so please set me straight if I am missing something important. Hopefully though, there is a polymer way to do what I'm asking.


回答1:


Your observer usage in 2.0 seems correct already, and I think you might be seeing a bug in the 2.0-preview branch. I recommend creating a GitHub issue for this, so that the Polymer team could confirm/clarify.

FWIW, the issue does not occur in Polymer 1.x (i.e., the observer is only invoked for the newly added item), as seen in this demo:

HTMLImports.whenReady(() => {
  class EditorElement {
    beforeRegister() {
      this.is = 'editor-element';
      this.properties = {todo: Object};
      this.observers = ["observe(todo.description)"];
    }

    observe(p1) {
      console.log("Observed change for TODO item description: "+p1);
    }
  }
  Polymer(EditorElement);

  class ListElement {
    beforeRegister() {
      this.is = 'list-element';

      this.properties = {
        list: {
          type: Array,
          value: () => []
        }
      };
    }

    _pushItem() {
      this.push("list", {description: `item ${this.list.length}`});
    }
  }
  Polymer(ListElement);
});
<head>
  <base href="https://polygit.org/polymer+1.8.1/components/">
  <script src="webcomponentsjs/webcomponents-lite.js"></script>
  <link rel="import" href="polymer/polymer.html">
</head>
<body>
  <list-element></list-element>

  <dom-module id="editor-element">
    <template>
      <div>Editor for [[todo.description]]</div>
    </template>
  </dom-module>
  
  <dom-module id="list-element">
    <template>
      <button on-click="_pushItem">Push item</button>

      <template is="dom-repeat" items="{{list}}">
        <div class="item">
          <editor-element todo="{{item}}">
          </editor-element>
        </div>
      </template>
    </template>
  </dom-module>

</body>


来源:https://stackoverflow.com/questions/42561573/in-polymer-2-0-how-to-observe-edits-to-properties-of-an-object-bound-to-an-eleme

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!