2

Basically what I want is to be able to add an 'onTap' attribute to my polymer button:

<paper-button onTap={this.handleTap}></paper-button>

So far I've tried the following approaches. The first four don't work, and the last two I find extremely unpalatable:

1) Write a custom react event plugin. This doesn't work for several reasons. Although at first glance it appears that you could add the 'tap' event to the set of events that React listens for, but there's no way to extend the topEventMapping table in ReactBrowserEventEmitter.js.

(One wonders how this code could possibly work, and the answer is likely that it doesn't - it's old.)

(A related problem is that the react plugin system is very weird, it seems to go out of its way to prevent anyone from adding new plugins - like you have to reset the entire event system and re-register all the built-in plugins if you want to add a new one.)

2) Create a mixin class that adds a 'tap' event listener to the root element of a react component. The mixin would look at the event target and get the name of the handler function from the attribute and dispatch the event to it.

This doesn't work because events originating from web components don't propagate to react components correctly, according to this article. So the event listener is never triggered.

3) Add an event listener on the window object and then route the event to the originating component. Although the event does get received by the window listener, there's no method to locate a react component given an element reference. (At least, not in the version of react that works with Meteor 1.2.)

4) Do a querySelector search on all DOM elements that have an 'onTap' attribute, and add an event listener on each one individually. This could be done in a mixin class to the react component.

The problem is that there's no way to exclude elements in child components from the querySelector results, so if you have nested react components each having web components inside of them, the events will trigger multiple handlers.

5) Wrap every web component in a react component. While this is the approach recommended by React, it's a huge amount of work (I'm using dozens of Polymer components, each of which has many attributes) and it's both inefficient in terms of code bloat and anti-idiomatic - the resulting HTML code no longer looks like Polymer code.

6) Use 'ref' to get a reference to each web component and manually add a listener to each one. This works, but it's ugly and clutters up the code a lot (remember you also have to unsubscribe as well). My whole reason for wanting 'onTap' is to that I can avoid having to write all this boilerplate.

Talin
  • 1,397
  • 2
  • 15
  • 30
  • Are you mixing polymer and react? that part confused me. And what's the difference between onTap and onClick? – Gaston Sanchez Feb 17 '16 at 05:49
  • Yes, I'm mixing polymer and react - so far they seem to work nicely together and there's very little functional overlap between them. onTap is different than onClick, it's got special logic for touch events, keyboard shortcuts and other kinds of input. – Talin Feb 17 '16 at 22:51
  • BTW just a follow up, I eventually abandoned this approach, now I'm using React-Bootstrap and it's not bad. It doesn't have as many fancy widgets as some of the other kits out there but to be honest our in-house UX style guide is just enough different from the material design standard that we just need a basic set of behaviors that we can write our own styles for. – Talin Oct 31 '16 at 04:44

1 Answers1

0

You can try to use xeact.

import xeact, {dispatchEvent, Component} from 'xeact';

@xeact('paper-button')
export default class PaperButton extends Component {

    handleTap() {
        dispatchEvent(this, 'tap' , {
            data
        });
    }

    render() {
        return <div onClick={() => {this.handleTap()}} />
    }
}

then use it as web-components in html

<x-paper-button></x-paper-button>
<script>
    document.querySelector('x-paper-button').addEventListener('tap', 
    function(){
        // onTap
    })
</script>