Saturday, April 19, 2014

Polymer Ready for Outside Changes


What are we doing tonight Brain? The same thing we do every night, Pinky—trying to see if something that didn't work two months back in Polymer works now.

This is proving to be a rough time to release a book on Polymer. My self-imposed deadline for edition 1.1 is tomorrow, but it's looking more and more like a 1.2 may need to follow sooner rather than later. Still, I have a deadline so I need to do what I can to get the book in the best shape possible.

Tonight the thing that didn't work a while back was establishing attribute observers on Polymer elements—from outside the Polymer. I first ran into this issue while trying to get Angular and Polymer attributes playing nicely. Pushing changes from Angular down to Polymer worked just fine, but it took quite a bit of fiddling for Angular to see changes from Polymer (eventually resulting in the angular-bind-polymer package).

I wound up incorporating a similar solution into a general approach to watching from the outside. I may not need it after, though it does help to explain the concept before the Angular chapter so I may keep it regardless.

So the real question is, do I need the onPolymerReady hack under normal circumstances? The onPolymerReady hack provided a callback that would be executed as soon as the element in question was decorated by Polymer:
function onPolymerReady(el, fn) {
  if (el.$) fn();
  else setTimeout(function(){onPolymerReady(el, fn);}, 10);
}
Here, I am waiting 10 milliseconds between checking the target element for Polymer's dollar-sign property. That worked well in angular-bind-polymer, but it seems like overkill on simpler pages like this test page. If I comment out the call to onPolymerReady and just start my watcher function immediately:
document.addEventListener("DOMContentLoaded", function(event) {
  var el = document.querySelector('hello-you');
  // onPolymerReady(el, function(){
    watchPolymer(el);
  // });
});
It still does not work:
unresolved is now: undefined watcher.js:14
your_name is now: a watcher.js:14
your_name is now: as watcher.js:14
your_name is now: asd watcher.js:14
your_name is now: asdf watcher.js:14
The element starts off as undefined, which would result in errors (especially when used with Angular). That said, it does work eventually. After a few changes to the Polymer element, the watcher function eventually does see real changes, which is news to me. I do wonder if this is new with MutationObservers (which are used under the covers) or with Polymer. This might make the Angular solution a little easier. Something to check another day.

What does work with no errors—and is more along the lines of the Polymer Way™—is listening for the polymer-ready event:
document.addEventListener("DOMContentLoaded", function(event) {
  var el = document.querySelector('hello-you');
  // onPolymerReady(el, function(){
  document.addEventListener('polymer-ready', function(){
    watchPolymer(el);
  });
});
Then it works from the outset.

Of course, in the JavaScript world, there is no guarantee of script load order and execution. This is why I ran into trouble with AngularJS and Polymer. Which library loaded first? Had the polymer-ready event already fired by the time the Angular directive was evaluated? Had it fired by the time the directive tried to bind to the Polymer element's attribute?

I have to agree that the feedback that prompted tonight's investigation was correct. I do not need this onPolymerReady hack—at least not to solve the problem presented in the chapter. So I will ease back on some of the claims that I make therein. Still, I think that I will leave this in place—of only to avoid discussing this craziness in the already tight Angular chapter.

And now, on to editing!



Day #39

1 comment: