Wednesday, December 11, 2013

Can't Listen for Events on Parent Shadow Root


One of the things that I hope to gain by writing Patterns in Polymer in both JavaScript and Dart is a deeper understanding of what Polymer really is. Not just how I can bend it to my will, but how it really wants me to code it.

To that end, I have a solution for communicating from parent Polymers to descendant Polymers (which might possibly reside in a shadow DOM). The solution involved the following DOM structure:
    <store-changes>
      #shadowRoot
      <store-changes-load></store-changes-load>
      <div contenteditable>
        <!-- actual changes occur here -->
      </div>
    </store-changes>
The <store-changes> element fires events on its shadowRoot and the <store-changes-load> element listens to that same shadowRoot. That seemed to work, at least when working with Polymer.dart. But what about in regular Polymer?

I run into a few minor issues converting my Dart Polymers over to JavaScript. Mostly, I find that, where I could hook into the ready() lifecycle callback in Dart, I need to use enteredView() in JavaScript:
<polymer-element name="store-changes-load">
  <script>
    Polymer('store-changes-load', {
      enteredView: function() {
        this._findElements();
        this._listenForLoad();
      },
      // ...
    });
  </script>
</polymer-element>
With ready() in JavaScript, the shadowRoot is undefined, which, I suppose makes some sense. Mental note made.

Unfortunately, that is not all that I find. I verify that the shadowRoot from the parent <store-changes> element is the same thing as the parentNode from the <store-changes-load child element. Despite this, I cannot listen for events on that parent node. When I listen for events, even events created in the same <store-changes-load> child element, I see nothing:
<polymer-element name="store-changes-load">
  <script>
    Polymer('store-changes-load', {
      // ...
      _listenForLoad: function() {
        this.parentNode.addEventListener('store-changes-load', function(e){
          // I see nothing in here
          console.log('yo');
          var current = e.detail['current'];
          console.log(current);
        });

        // Dispatching this should show hte event above///
        var e = new CustomEvent('store-changes-load', { 'detail': {current: 'foo'} });
        this.parentNode.dispatchEvent(e);
      },
      // ...
    });
  </script>
</polymer-element>
Doing the same in the parent <store-changes> parent Polymer works fine. So it would seem that, at least in the JavaScript version of Polymer that there is no way for a child element to listen for (or generate) events on the document fragment that serves as the shadow root.

So it seems that it's back to the drawing board on how best to communicate from parent to child in the shadow DOM.

Day #962

3 comments:

  1. what about binding published attributes declaratively

    ReplyDelete
  2. shouldn't have used < > ...
    My code snipped got swallowed
    next try ...

    <child childAttr="{{parentAttr}}">

    I had some issues with this though but when all bugs are fixed this should work fine.

    ReplyDelete
    Replies
    1. Yup, that's what I wound up trying “after hours.” That does indeed seem to be the right way of approaching this problem. Gonna try in tonight in Dart just to be sure.

      Thanks for the suggestion -- it feels like this may be the Polymer Way™ :)

      Delete