Pregunta Enlace de datos entre dos elementos de polímero utilizando el polímero 1.0


Pregunta

En el siguiente ejemplo, ¿cómo puedo unir el obj.name variable del <input> campo en <test-element2> a <test-element> ?


Fondo:

A continuación está mi código. Tengo dos elementos de polímero. test-element tiene los datos vinculados a obj.name. test-element2 tiene un campo de entrada que es observado por la función objChanged. Cualquier valor que cambie en el campo de entrada cambia y se imprime en test-element2 pero el cambio no se refleja en test-element. ¿Puede cualquier cuerpo ayudar a obtener el valor reflejado en test-element1? Tengo una solución usando this.fire("object-change") para cuando cambia el texto, pero estoy buscando una solución sin usar oyentes de eventos.

Una cosa más es que necesito crear un elemento desde el script y no se puede codificar en el DOM HTML.


Código:

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Demo</title>

    <script src="../../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
    <link rel="import" href="../../bower_components/polymer/polymer.html"/>
</head>

<body>
    <dom-module id="test-element">
        <template>
            <div>Hello <span>{{obj.name}}</span></div>
        </template>

        <script>
            TestElement = Polymer({
                is: "test-element",

                properties: {
                    "obj": {
                        type: Object,
                        notify: true
                    }
                },

                observers: [
                    "objChanged(obj.name)"
                ],
                "objChanged": function() {
                    var that = this;
                    console.log("First element in 1",that.obj);
                }
            });
        </script>
    </dom-module>


    <dom-module id="test-element2">
        <template>
            <input value="{{obj.name::input}}"/>
        </template>

        <script>
            Polymer({
                is: "test-element2",

                properties: {
                    "obj": {
                        type: Object,
                        notify: true,
                        value: {
                            "name": "Charlie"
                        }
                    }
                },

                observers: [
                    "objChanged(obj.name)"
                ],

                ready: function() {
                    var element = new TestElement();
                    element.set("obj", this.obj);
                    this.appendChild(element);
                },

                "objChanged": function() {
                    console.log("changed in test-element2:", this.obj);
                }
            });
        </script>
    </dom-module>


    <test-element2></test-element2>
 </body>
</html>

5
2017-07-22 18:19


origen


Respuestas:


Si incluye <test-element> en el <template> de test-element2 puede evitar el uso de escuchas u observadores de eventos. De este modo test-element2 maneja el enlace de datos entre input y <test-element> para ti.

A continuación se muestra un ejemplo de trabajo en vivo que mantiene el obj propiedad como lo has configurado en tus elementos.

<script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="test-element">
  <template>
    <div>Hello <span>[[obj.name]]</span>
    </div>
  </template>
  <script>
    TestElement = Polymer({
      is: "test-element",

      properties: {
        "obj": {
          type: Object,
          notify: true
        }
      }
    });
  </script>
</dom-module>
<dom-module id="test-element2">
  <template>
    <input value="{{obj.name::input}}" />
    <test-element obj="[[obj]]"></test-element>
  </template>

  <script>
    Polymer({
      is: "test-element2",

      properties: {
        "obj": {
          type: Object,
          notify: true,
          value: {
            "name": "Charlie"
          }
        }
      }
    });
  </script>
</dom-module>
<test-element2></test-element2>

Actualmente, enlace de datos imperativo  no es compatible con Polymer 1.0 fuera de <template is="dom-bind">.

Yo recomendaría configurar observadores como en el siguiente ejemplo o ajustar sus requisitos para incluir <test-element> en test-element2.

button {
  display: block;
}
<script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents.min.js"></script>
<link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="test-element">
  <template>
    <div>Hello <span>[[obj.name]]</span>
    </div>
  </template>
  <script>
    TestElement = Polymer({
      is: "test-element",

      properties: {
        obj: {
          type: Object,
          notify: true
        }
      }
    });
  </script>
</dom-module>
<dom-module id="test-element2">
  <template>
    <input value="{{obj.name::input}}" />
  </template>

  <script>
    Polymer({
      is: "test-element2",

      properties: {
        obj: {
          type: Object,
          notify: true,
          value: {
            "name": "Charlie"
          }
        }
      },
      observers: ["objNameChanged(obj.name)"],
      objNameChanged: function(newValue) {
        Polymer.dom(document).querySelectorAll("test-element").forEach(function(element) {
          element.notifyPath("obj.name", newValue);
        });

        Polymer.dom(this.root).querySelectorAll("test-element").forEach(function(element) {
          element.notifyPath("obj.name", newValue);
        });
      }
    });
  </script>
</dom-module>
<test-element2></test-element2>
<button>Add test-element to <em>test-element2</em>
</button>
<button>Add test-element to <em>body</em>
</button>
<script>
  var testElement2 = document.querySelector("test-element2");

  var createTestElement = function(insertPoint) {
    var testElement = new TestElement();
    testElement.notifyPath("obj.name", testElement2.obj.name);

    insertPoint.appendChild(testElement);
  };

  document.querySelector("button:nth-of-type(2)").addEventListener("click", function() {
    createTestElement(Polymer.dom(document).querySelector("body"));
  });

  document.querySelector("button").addEventListener("click", function() {
    createTestElement(Polymer.dom(testElement2.root));
  });
</script>


4
2017-07-22 19:18



Si eliges dividir tus elementos en sus propios archivos, podrías seguir este ejemplo de Plunker (por Nazerke) demostrando un enlace de datos bidireccional al tener un componente que observa la propiedad de otro.

Código

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="parent-element.html">
  <link rel="import" href="first-child.html">
  <link rel="import" href="second-child.html"> </head>

<body>
  <parent-element></parent-element>
</body>

</html>

parent-element.html

<link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="parent-element">
  <template>
    <first-child prop={{value}}></first-child>
    <second-child feat1={{prop}}></second-child> In parent-element
    <h1>{{value}}</h1> </template>
  <script>
    Polymer({
      is: "parent-element",
      properties: {
        value: {
          type: String
        }
      },
      valueChanged: function() {
        console.log("value changed");
      }
    });
  </script>
</dom-module>

first-child.html

<link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="first-child">
  <template>
    <p>first element.</p>
    <h2>{{prop}}</h2> </template>
  <script>
    Polymer({
      is: "first-child",
      properties: {
        prop: {
          type: String,
          notify: true
        }
      },
      ready: function() {
        this.prop = "property";
      }
    });
  </script>
</dom-module>

second-child.html

<link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="second-child">
  <template>
    <p>Second element.</p>
    <h2>{{feat1}}</h2> </template>
  <script>
    Polymer({
      is: "second-child",
      properties: {
        feat1: {
          type: String,
          notify: true,
          value: "initial value"
        }
      },
      ready: function() {
        this.addEventListener("feat1-changed", this.myAct);
      },
      myAct: function() {
        console.log("feat1-changed ", this.feat1);
      }
    });
  </script>
</dom-module>

3
2017-07-24 09:34



Si eliges dividir tus elementos en sus propios archivos, podrías usar <iron-meta> a enlace de datos bidireccional como se describe aquí:

Código de ejemplo:

<iron-meta key="info" value="foo/bar"></iron-meta>
...
meta.byKey('info').getAttribute('value').

o

document.createElement('iron-meta').byKey('info').getAttribute('value');

o

<template>
  ...
  <iron-meta id="meta"></iron-meta>
  ...
  this.$.meta.byKey('info').getAttribute('value');
  ....
</template>

1
2017-07-24 09:37



Si eliges dividir tus elementos en sus propios archivos, podrías usar <iron-localstorage> a enlace de datos bidireccional como se describe aquí.

Código de ejemplo:

<dom-module id="ls-sample">
  <iron-localstorage name="my-app-storage"
    value="{{cartoon}}"
    on-iron-localstorage-load-empty="initializeDefaultCartoon"
  ></iron-localstorage>
</dom-module>

<script>
  Polymer({
    is: 'ls-sample',
    properties: {
      cartoon: {
        type: Object
      }
    },
    // initializes default if nothing has been stored
    initializeDefaultCartoon: function() {
      this.cartoon = {
        name: "Mickey",
        hasEars: true
      }
    },
    // use path set api to propagate changes to localstorage
    makeModifications: function() {
      this.set('cartoon.name', "Minions");
      this.set('cartoon.hasEars', false);
    }
  });
</script>

1
2017-07-24 09:41



<dom-module id="test-element">
  <template>
    <div>Hello <span>{{name}}</span></div>
  </template>
  <script>
    Polymer({
      is: "test-element",

      properties: {
        name: String
      }
    });
  </script>
</dom-module>

<dom-module id="test-element2">
  <template>
    <input value="{{name::input}}"/>
    <test-element name="[[name]]"></test-element>
  </template>
  <script>
    Polymer({
      is: "test-element2",

      properties: {
        name: String
      }
    });
  </script>
</dom-module>

0
2017-07-22 18:53