Polymer 1.0: Как передать событие элементу child-node без использования «железных сигналов»?

В этом ответе на переполнение стека предлагается использовать <iron-signals> для трансляции события вниз по дереву DOM к пользовательскому элементу.

Ниже я задаю другой вопрос.

Вопрос

Как мне:

  • передать событие в прямой дочерний узел (пользовательский элемент)
  • от родителя (пользовательский элемент)
  • без использования <iron-signals>?

Код

Это то, что у меня есть до сих пор. Но это не работает.

parent-element.html
<dom-module id="parenet-element">   
  <template is="dom-bind">
    <child-element></child-element>
    <paper-button on-tap="_handleTap"></paper-button>
  </template>
</dom-module>
<script>
  (function(){
    Polymer({
      is: 'parenet-element',
      _handleTap: function() {
        this.fire("my-event");
      }
    });
  })();
</script>
child-element.html
<dom-module id="child-element"> 
...
</dom-module>
<script>
  (function(){
    Polymer({
      is: 'child-element',
      listeners: {
        "my-event": "foo"
      },
      foo: function(){
        // Do stuff
      }
    });
  })();
</script>

person Let Me Tink About It    schedule 24.09.2015    source источник


Ответы (3)


Вы определенно можете. Без iron-signals у вас есть три варианта (из которых я сейчас знаю):

  1. Получите родителя и попросите ребенка прикрепить прослушиватель событий к родителю
  2. Родитель может заставить дочерний элемент запускать одно и то же событие
  3. Вы упомянули, что события только идут вверх. Затем вы можете заставить дочерний элемент прослушивать document запуск этого события (но я думаю, что это плохо)

Вот пример

<!doctype html>
<html>

<head>
  <base href="http://polygit.org/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link href="polymer/polymer.html" rel="import">
</head>

<body>
  <dom-module id="parent-element">
    <template>
      <child-element></child-element>
      <button id="btn" on-tap="_fireParentEvent1">Fire 1!</button>
      <button id="btn" on-tap="_fireParentEvent2">Fire 2!</button>
      <button id="btn" on-tap="_fireParentEvent3">Fire 3!</button>
    </template>
  </dom-module>
  <dom-module id="child-element">
    <template>
      <style>
        :host {
          display: block;
        }
      </style>
      <span id="changeMe">Message</span>
    </template>
  </dom-module>

  <parent-element></parent-element>
  <script>
    (function registerElements() {
      Polymer({
        is: 'parent-element',
        listeners: {
          'event-two': '_attachToChild'
        },
        _attachToChild: function(e) {
          // the parent makes the child fire an event
          var childElement = Polymer.dom(this.root).querySelector('child-element');
          childElement.fire('event-two', e.detail);
        },
        _fireParentEvent1: function(e) {
          // the parent fires an event
          this.fire('event-one', {
            message: 'hello'
          });
        },
        _fireParentEvent2: function(e) {
          this.fire('event-two', {
            message: 'goodbye'
          });
        },
        _fireParentEvent3: function(e) {
          // the parent fires an event
          this.fire('event-three', {
            message: 'game over'
          });
        }
      });

      Polymer({
        is: 'child-element',
        listeners: {
          'event-two': '_handleEventTwo'
        },
        ready: function() {
          var parent = this.parentNode;

          // the child listens to the parent's event
          parent.addEventListener('event-one', function(e) {
            this.$.changeMe.innerHTML = e.detail.message;
          }.bind(this));

          // listen to the document level event (since events travel up)
          // but this option is difficult to control
          document.addEventListener('event-three', function(e) {
            this.$.changeMe.innerHTML = e.detail.message;
          }.bind(this));
        },
        _handleEventTwo: function(e) {
          this.$.changeMe.innerHTML = e.detail.message;
        }
      });
    })();
  </script>
</body>

</html>

person Neil John Ramal    schedule 24.09.2015

С Polymer 1.2.4, как описано здесь, мы можем используйте параметры метода fire и заставьте дочерний узел (оставаясь все еще внутри родительского элемента) запускать (и, конечно, сначала прослушивать) событие:

this.fire('test', {
    user: {
        name: 'Marios',
        gender: 'male'
    }
}, {
    node: Polymer.dom(this.root).querySelectorAll('my-child-element'),
    bubbles: false
});

Мы запустили пользовательское событие из элемента, но эмиттером является my-child-element, поэтому мы можем прикрепить прослушиватель к объекту listeners. Мы также предотвращаем всплытие события, чтобы оно не перемещалось вверх по пути родительских элементов. Типичным слушателем может быть:

Polymer({
    is: 'my-child-element',

    properties: {
        ...
    },
    listeners: {
        'test': '_myHandler'
    },
    _myHandler: function(e) {
        var user = e.detail.user;
        ...
    }
});
person Marios Fakiolas    schedule 07.02.2016
comment
это работает, но что, если к child-element прикреплен dom-repeat? например, <dom-module id="parent-element"> <template is="dom-repeat" it> <child-element></child-element> </template> </dom-module> в этой ситуации querySelector просто вызовет событие для первого элемента, которому он соответствует, а querySelectorAll вызовет событие для всех элементов одновременно. Я хочу по одному. Есть идеи? - person Yoshita Arora; 26.07.2017

@arthur in the Polymer Slack site says:

События, как правило, идут вверх по дереву DOM. Спускаясь вниз, вы можете использовать привязку данных или вызвать метод.

Сайт Polymer Slack

person Let Me Tink About It    schedule 24.09.2015
comment
Не удается получить доступ к прикрепленной ссылке, не могли бы вы вставить любой пример, если он его предоставил. Спасибо! - person Srikanth Rayabhagi; 06.09.2016