Javascript Polymer Event for Text Changed

I’m really liking the level of abstraction that Polymer affords me at the moment. I can write semantic HTML and still do all the markup I want. For example, one of the things I am working on right now is a custom element that encapsulates a written box. You probably see these in written forms all over the place. Underneath is a title, like “Address” and you write above the line. With a little bit of bootstrap, I wanted to emulate that sort of thing.

My HTML page starts off basically enough:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Test HTML Page</title>

    <script src="lib/webcomponentsjs/webcomponents.min.js"></script>
    <link href="lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="css/main.css" rel="stylesheet">

    <link rel="import" href="elements/dnd-dropdown/dnd-dropdown.html">
    <header class="container">
        <div class="row">
            <dnd-dropdown class="col-md-4" id="dndAddress" field="Address">123 Main Street</dnd-dropdown>
    <section id="scripts">
        <script src="lib/jquery/dist/jquery.min.js"></script>
        <script src="lib/bootstrap/dist/js/bootstrap.min.js"></script>

The elements/dnd-dropdown/dnd-dropdown.html is where the basic stuff happens.

<link rel="import" href="../../lib/polymer/polymer.html">
<link rel="import" href="../font-architects-daughter.html">

<polymer-element name="dnd-dropdown" attributes="field">
        <link rel="stylesheet" href="dnd-dropdown.css">
        <div id="c">
            <div class="dndValue"><content></content></div>
            <div class="dndTitle">{{field}}</div>
            field: "...",

I’m using the Architects Daughter font from Google Fonts for this purpose. Polymer core components included a font-roboto.html file that gives the basic pattern. Spoiler: it’s just a <link> element from the Google Fonts website. With all the styling that I have done, the page looks like this:


This isn’t a post about the basics of Polymer though. This is, after all, a very basic Polymer custom element. This is about events. In particular I want to capture when something outside my custom element alters the address. I am setting up the event handler in the Polymer ready function like this:

            field: "...",

            ready: function () {
                // Do something here

The ready method is called when the polymer-ready event fires, which happens when the custom element is completely set up and all the machinations that Polymer does for you behind the scenes has completed. It’s a great place to set up custom event handlers.

The question is – what goes in that ready function. My first thought was to use the onMutation call. This looks for DOM changes in the children and seemed like the right way. The code is relatively simple as well:

            ready: function () {
                this.onMutation(this, function () {
                    console.log("Something changed");

To test it, I brought up the F12 Developer Tools and typed in the following in the console:

var x = document.querySelector("dnd-dropdown");
x.innerHTML = "Something new";

I am, of course, looking for the console to print Something changed. To save you the agony, it didn’t work. The onMutation event handler did not fire. At that point, I tried a bunch of things with events, but nothing seemed to work. I even turned to Stack Overflow.

Then I went away and did something else – I was reading the Javascript pages on MDN to gain more insight into events in general. I came across MutationObserver – a new thing. It only works in IE11 and above, but has good support in Chrome and Mozilla engines. I was a little hesitent because of the IE11 support, but it seemed like a good option.

Firstly, let’s check out the code:

            readyjavascriptfunction () {
                var that = this, 
                    observer = new MutationObserver(function (mutations) {
                    console.debug("Something changed!");
          "textChanged", { 
                        field: this.field, 
                        value: mutations[0].target.textContent 
                }).observe(this, { 
                    childList: true, 
                    subtree: true, 
                    characterData: true 

First of all I checked Chrome support. The MutationObserver callback always got called with 1 element in mutations. If I were to look at that one element, I saw an object with a target parameter that was the text node (with a textContent that was the new value). In addition, I saw a type parameter that was “characterData”. This seemed perfect to me.

Then I tried Internet Explorer Technical Preview. This same code generated an array of 3 mutations. There are 3 levels of DIV elements between my <dnd-dropdown> element and the <content> element in the shadow DOM, so this makes sense. Each mutation had a target parameter that was identical. In this case the target parameter was an HTMLElement pointing to the <dnd-dropdown> node and the type parameter was “childList”.

If I removed the “subtree” configuration option, no mutations were observed – the same behavior as the onMutation version. Since Chrome fires a characterData mutation and Internet Explorer fires a childList mutation, I need both of those.

To assist with anyone else doing this, I wrapped this in a new “textChanged” event that others can listen to. Another node in my page could register for the textChanged event using addEventListener. For example, I have a google maps element that re-centers the map when the address changes. I can use something like:

var addr = document.querySelector("#dndAddress");
addr.addEventListener("textChanged", this.recenterMap().bind(this), false);

The Polymer method of doing this is to have another custom element that acts as a broker between two distinct custom elements. This method allows a more cooperative mechanism, providing events as the message passing mechanism.