Wednesday, October 1, 2014

Bootstrap CSS with Polymer (Revisited)


I maintain that there are times that developers will want web components to look like the rest of their site, not like Material Design. Toward that end, I include a chapter on Bootstrap CSS in Patterns in Polymer. Today, I double check that my solution stills works after upgrading all code the latest versions of Polymer.dart (for the Dart version of the book) and Polymer (for the JavaScript version of the book).

And, thankfully, my solution does continue to work:



One could certainly argue that this solution trades one popular-on-the-verge-of-overused styling approach for another. I would probably agree. The point is not to use a specific style, just to use a common style to validate an approach.

At the risk of spoiling the joy of reading the chapter, the solution boils down to an @import of the common CSS:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="pricing-plan" attributes="name type size">
  <template>
    <div class="col-md-{{size}}"><!- ... --></div>
    <style>
      @import '../bower_components/bootstrap/dist/css/bootstrap.min.css';
    </style>
  </template>
  <script src="pricing_plan.js"></script>
</polymer-element>
There is a little more to the solution (so really, you should read the book), but that is the gist.

But this got me thinking, perhaps the <apply-author-styles> custom Polymer element would work as well. So, in the JavaScript version of the code, I install it with Bower:
$ bower install --save eee-c/apply-author-styles
...
bower apply-author-styles#*               install apply-author-styles#434679b8da
bower core-ajax#~0.3.2                    install core-ajax#0.3.6

apply-author-styles#434679b8da bower_components/apply-author-styles
├── core-ajax#0.3.6
└── polymer#0.4.0

core-ajax#0.3.6 bower_components/core-ajax
└── polymer#0.4.0
Then, in my Polymer element HTML definitions, I remove the @import style and instead add the <apply-author-styles> tag:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import"
      href="../bower_components/apply-author-styles/apply-author-styles.html">
<polymer-element name="pricing-plan" attributes="name type size">
  <template>
    <apply-author-styles></apply-author-styles>
    <div class="col-md-{{size}}"><!-- ... -></div>
  </template>
  <script src="pricing_plan.js"></script>
</polymer-element>
And that works perfectly:



That is nice. I do not know if I will offer that as the solution to applying external styles in Patterns in Polymer, but it seems worth a mention. Worth it if it works in Dart as well.

So I switch over to the Dart version of the chapter code, which is configured to install Bower components in lib/elements by way of a .bowerrc file:
$ cat .bowerrc
{
  "directory": "lib/bower_components"
} 
I again execute bower install --save eee-c/apply-author-styles, this time in my Dart project.

I update my element to use the Bower installed <apply-author-styles>:
<link rel="import" href="../../../packages/polymer/polymer.html">
<link rel="import"
      href="../bower_components/apply-author-styles/apply-author-styles.html">
<polymer-element name="pricing-plan">
  <template>
    <apply-author-styles></apply-author-styles>
    <div class="col-md-{{size}}"><!-- ... --></div>
    <!-- <style> -->
    <!--   @import '/packages/bootstrap_example/assets/bootstrap.min.css'; -->
    <!-- </style> -->
  </template>
  <script type="application/dart" src="pricing_plan.dart"></script>
</polymer-element>
But run into problems that I have seen before. Actually, when I saw this previously, the error was much more helpful. This time, all I get is:
Uncaught TypeError: undefined is not a function    polymer.js:96
  (anonymous function)                             polymer.js:96
  (anonymous function)                             polymer.js:99
And:
Exception: NoSuchMethodError: method not found: 'whenPolymerReady'
Receiver: Instance of 'JsFunction'
Arguments: [Closure: () => dynamic]               package:polymer/src/loader.dart:103
Eventually, I realize that the polymer.js generating the error is the one installed via Bower, not the one bundled with Polymer.dart. So I have to do what I did before: hand-edit core-xhr.html in lib/bower_components to point to the Polymer.dart version. Horrible.

I do not think this is easily solved. It would seem that any JavaScript Polymer element that depends on core-xhr and, by extension, core-ajax, will not be usable in Polymer.dart. Since <apply-author-styles> is such a beast, it would seem that I am out of luck, leaving the @import solution as the best and only available. Unless I am willing to rewrite and maintain apply-author-styles in Dart as well...



Day #200

5 comments:

  1. Try having a look at core_elements/generate_dart_api.dart. It might answer the problem with using JS elements in dart. Or even better, try this: https://pub.dartlang.org/packages/custom_element_apigen. I knew I saw a post about this, earlier on.

    ReplyDelete
    Replies
    1. Cool. I'll have a look. All I really need is a programmatic way to fix the reference to polymer.html (not API access). But if that happens to fix core-xhr along the way, it'd be a nice bonus :)

      Delete
  2. Hey, I didn't know about the `` element. Do you have some resources on that one? Because (as you might know) there was an `applyAuthorStyles` property one could use to make styles of Shadow DOM from the outside world possible. However, this property has been refused and now we have `::shadow` and `/deep/` combinator selectors to cross style boundaries.

    ReplyDelete
    Replies
    1. The apply-author-styles element resides at: https://github.com/eee-c/apply-author-styles.

      Some of the thought behind it and the implementation were described at: http://japhr.blogspot.com/2014/06/a-tag-named-apply-author-styles.html.

      I'm still unsure if it's a good idea (any more so than the original applyAuthorStyles property), but it seems to do the trick in certain cases.

      Delete
  3. It's a nice approach. Problem is that the components is not styled until the ajax request is done. Then, the element looks unstyled for a flash of moment before the ajax request is done. I prefer to use the @import.

    ReplyDelete