Search code examples
polymerweb-component

how to use mutation observers in polymer 1.0


I cannot find documentation on how to use mutation observers that are part of the webcomponents.js polyfills. Can some give me an example.

I want to observe changes in an element pointed in the snap shot.

enter image description here


Solution

  • MutationObserver works the same or very close to the same under the polyfill (webcomponents.js) as it does natively. You can learn more about MutationObserver here.

    You can setup MutationObserver in the ready function of your custom element (data-tree). If you want to observe changes to elements added after the ready function is called you should setup/re-setup MutationObserver after the elements are added.


    Example MutationObserver in ready function:

    ready: function () {                    
        var mutationHandler = function (mutation) {
            var newValue = mutation.target.getAttribute("filters");
            var oldValue = mutation.oldValue;
    
            // filterList is a method on the element's (data-tree) prototype.
            this.filterList(mutation.target, newValue, oldValue);
        }.bind(this);
    
        var observerCallback = function (mutations) {
            mutations.forEach(mutationHandler);
        };
    
        var mutationObserver = new MutationObserver(observerCallback);
    
        // You can change the querySelectorAll to select other elements or narrow the results.
        // For example, Polymer.dom(this.root).querySelector("#all > li:nth-child(1)");
        var targetNodes = Polymer.dom(this.root).querySelectorAll("li");    
        targetNodes.forEach(function (targetNode) {
            mutationObserver.observe(targetNode, {
                attributes: true,
                attributeOldValue: true,
                attributeFilter: ["filters"]
            });
        });
    }
    


    Below is a working example using some of the code from the image in the question.

    <script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents.min.js"></script>
    <link rel="import" href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
    <link rel="import" href="bower_components/iron-icons/iron-icons.html" />
    <link rel="import" href="bower_components/paper-fab/paper-fab.html" />
    <dom-module id="data-tree">
      <style>
        :host {
          font-family: "Segoe UI Semilight", "Segoe UI", "Segoe", Tahoma, Helvetica, Arial, sans-serif;
          font-size: 15px;
        }
        paper-fab {
          border-radius: 5px;
          height: 2px;
          transform: scale(0.5);
          width: 1px;
        }
        ul {
          list-style-type: none;
        }
        li {
          margin: 20px;
        }
        li span {
          padding: 20px 10px;
        }
        .toggler {
          background: #9b9b9b;
        }
        .hidden ul {
          display: none;
        }
        /deep/ paper-material[elevation="1"].paper-material-0 {
          box-shadow: none;
        }
        /deep/ paper-material[elevation="1"].paper-material-0:hover {
          box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12), 0px 3px 1px -2px rgba(0, 0, 0, 0.2);
        }
      </style>
      <template>
        <div id="tree-container">
          <ul id="all">
            <li>
              <paper-fab icon="remove" class="toggler"></paper-fab>All
              <ul id="plants">
                <li>
                  <paper-fab icon="remove" class="toggler"></paper-fab>Plants
                  <ul id="plant-types"></ul>
                </li>
              </ul>
            </li>
          </ul>
        </div>
        <div id="mutation-record">
          <div>
            Current <em>filters</em> attribute: <strong id="new-value"></strong>
          </div>
          <div>
            Old <em>filters</em> attribute: <strong id="old-value"></strong>
          </div>
        </div>
      </template>
      <script>
        Polymer({
          is: "data-tree",
          ready: function() {
            var mutationHandler = function(mutation) {
              var newValue = mutation.target.getAttribute("filters");
              var oldValue = mutation.oldValue;
    
              this.filterList(mutation.target, newValue, oldValue);
            }.bind(this);
    
            var observerCallback = function(mutations) {
              mutations.forEach(mutationHandler);
            };
    
            var mutationObserver = new MutationObserver(observerCallback);
    
            // You can change the querySelectorAll to select other elements or narrow the results.
            // For example, Polymer.dom(this.root).querySelector("#all > li:nth-child(1)");
            var targetNodes = Polymer.dom(this.root).querySelectorAll("li");
            targetNodes.forEach(function(targetNode) {
              mutationObserver.observe(targetNode, {
                attributes: true,
                attributeOldValue: true,
                attributeFilter: ["filters"]
              });
            });
          },
          filterList: function(target, newValue, oldValue) {
            console.log(target);
            this.$["new-value"].textContent = newValue;
            this.$["old-value"].textContent = oldValue;
          }
        });
      </script>
    </dom-module>
    <data-tree></data-tree>
    <input type="text" />
    <button>Set Attribute</button>
    <script>
      document.querySelector("button").addEventListener("click", function() {
        var dataTree = Polymer.dom(document.querySelector("data-tree").root);
        var li = dataTree.querySelector("#all > li:nth-child(1)");
        li.setAttribute("filters", document.querySelector("input").value);
      });
    </script>