Polymer 1.0: How to pass an event to a child-node element without using <iron-signals>?

You definitely can. Without iron-signals you've got three options (that I currently know of):

  1. Get the parent and have the child attach an event listener to the parent
  2. The parent can have the child fire the same event
  3. You mentioned that events only go up. You can then make the child element listen to the document firing that event (but I think this is bad)

Here's an example

<!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>


With Polymer 1.2.4 as documented here we can use fire method options and force a child node (while still inside a parent element) to fire (and listen first of course) an event:

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

We fired a custom event from an element but the emitter is the my-child-element so in there we can attach a listener in the listeners object. We also prevent the event bubbling so this event won't move upwards following the parents elements path. A typical listener could be:

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

    properties: {
        ...
    },
    listeners: {
        'test': '_myHandler'
    },
    _myHandler: function(e) {
        var user = e.detail.user;
        ...
    }
});

@arthur in the Polymer Slack site says:

Events tend to go up the DOM tree. Going down, you can use a data binding or invoke a method.

Polymer Slack Site