Thursday, November 28, 2013

UI-less Polymer Elements


When I think of web components, I normally think of creating new UI elements. But I think one of the more intriguing things that is possible with them is the ability to create UI-less features that simply serve as a convenient way to get access to streams of information. Instead of creating JavaScript objects that receive AJAX responses, create a Polymer element that does and then bubbles events in the document like an HTML element.

To explore the idea, I am going to try to create a JavaScript Polymer element that listens for click events on a web page. I start with the usual <script> setup and a custom <click-sink> element in the body:
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Test</title>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type">
    <!-- 1. Load Polymer before any code that touches the DOM. -->
    <script src="scripts/polymer.min.js"></script>
    <!-- 2. Load component(s) -->
    <link rel="import" href="scripts/click-sink.html">
  </head>
  <body>
    <click-sink></click-sink>
  </body>
</html>
The backing element can then be nothing but a Polymer script that listens for events on the main document:
<polymer-element name="click-sink">
  <script>
    Polymer('click-sink', {
      enteredView: function() {
        this.ownerDocument.addEventListener('click', function(e){
          console.log('click');
        });
      }
    });
  </script>
</polymer-element>
And that works. When I click the page, I see "click" logged to the JavaScript console. It is of little use unless I transform that in some way. For tonight, I am content to transform that into a message that contains the X-Y coordinate at which the element was clicked. So I change the enteredView() method to:
      enteredView: function() {
        var that = this;
        this.ownerDocument.addEventListener('click', function(e){
          var xy = '' + e.clientX + ',' + e.clientY;
          that.fire('clicked', {msg: 'I got clicked at: ' + xy});
        });
      }
With that, I should be able to listen in my main document for the custom "clicked" event:
<!DOCTYPE html>
<html lang="en">
  <head><!-- load polymer stuff --></head>
  <body>
    <click-sink></click-sink>
  </body>
<script>
  document.addEventListener('clicked', function(e){
    console.log(e.detail.msg);
  });
</script>
</html>
Now, when I click on the page I get:
I got clicked at: 286,273
I got clicked at: 455,266
I got clicked at: 223,274 
Nice.

I am especially interested in extending this idea to web services and sockets. If the trouble of setting those up can be hidden behind a web component, leaving only streams of events, I think there can be some really fun possibilities. Which I will start to explore tomorrow.

Day #949

No comments:

Post a Comment