Polymer.jsでオブジェクトのメンバをバインドすると何故かstaticになるのはバグ?

投稿者: Anonymous

こういうCustom Element <test-01>があります

test-01.html

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-button/paper-button.html"/>

<polymer-element name="test-01" attributes="">
  <template>
    <h1>{{ obj.value }}!</h1>
    <paper-button on-click="{{ add }}">add</paper-button>
  </template>
  <script>
    (function () {
      Polymer({
        obj: {
          value: "ABC"
        },
        add: function () {
          this.obj.value += "1";
        }
      });
    })();
  </script>
</polymer-element>

ボタンを押すとaddが叩かれて、obj.valueを変更します。バインドされてるので<h1>中の表示もリアルタイムに更新されます。

これを複数個使うと、なぜかすべての<test-01>が同じ動きをします

index.html

<!doctype html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <title>polymer sandbox</title>
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="elements/test-01/test-01.html">
  </head>
  <body unresolved>
    <test-01></test-01>
    <test-01></test-01>
    <script src="scripts/app.js"></script>
  </body>
</html>

実際に動かしたものがこちら

01

バインド対象を文字列の変数にしてみます

<polymer-element name="test-01" attributes="">
  <template>
    <h1>{{ obj }}!</h1>
    <paper-button on-click="{{ add }}">add</paper-button>
  </template>
  <script>
    (function () {
      Polymer({
        obj: "ABC",
        add: function () {
          this.obj += "1";
        }
      });
    })();
  </script>
</polymer-element>

すると正常に動きます

02

前者で起こっていることの可能性としては

  • objが共有されている(like a static variable)
  • すべての<test-01>on-clickイベントが発火している

の2つが考えられますが、addconsole.log仕込んでみたところ、1回しか呼び出されてませんでした。

objが共有されるのって正しい挙動なんでしょうか?API developer guide – Polymer見てもこの書き方なら要素ごとのプロパティとして宣言されると思うんですけど、誰かPolymerやWebComponentsに詳しい方知ってたら教えてください

解決

確か Polymer() 内でのオブジェクトや配列は共有状態になり、
created: のコールバックで初期化する必要があったはずです。

<polymer-element name="test-01" attributes="">
  <template>
    <h1>{{ obj.value }}!</h1>
    <paper-button on-click="{{ add }}">add</paper-button>
  </template>
  <script>
    (function () {
      Polymer({
        created: function(){
          this.obj = {}
          this.obj.value = "ABC"
        },
        add: function () {
          this.obj.value += "1";
        }
      });
    })();
  </script>
<polymer-element>

また、今回の場合は publish でも回避することができます。

<polymer-element name="test-01" attributes="">
  <template>
    <h1>{{ obj1 }}!</h1>
    <h2>{{ obj2 }}!</h2>
    <paper-button on-click="{{ add1 }}">add1</paper-button>
    <paper-button on-click="{{ add2 }}">add2</paper-button>
  </template>
  <script>
    (function () {
      Polymer({
        publish: {
          obj1: "ABC",
          obj2: "EFG"
        },
        add1: function () {
          this.obj1 += "1";
        },
        add2: function () {
          this.obj2 += "1";
        }
      });
    })();
  </script>
</polymer-element>
回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *