Skip to content

Instantly share code, notes, and snippets.

@dnegstad
Last active January 2, 2019 17:50
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dnegstad/eee660aa32efd906082c to your computer and use it in GitHub Desktop.
Save dnegstad/eee660aa32efd906082c to your computer and use it in GitHub Desktop.
Polymer WebComponents in ember-cli >= 0.0.41
// Add these dependencies
"dependencies": {
"polymer": "Polymer/polymer#~0.5.1",
"core-elements": "Polymer/core-elements#~0.5.1",
"paper-elements": "Polymer/paper-elements#~0.5.1"
}
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var pickFiles = require('broccoli-static-compiler');
var mergeTrees = require('broccoli-merge-trees');
var vulcanize = require('broccoli-vulcanize');
var app = new EmberApp();
var polymerVulcanize = vulcanize('app', {
input: 'elements.html',
output: 'assets/vulcanized.html',
csp: true,
inline: true,
strip: false,
excludes: {
imports: ["(^data:)|(^http[s]?:)|(^\/)"],
scripts: ["(^data:)|(^http[s]?:)|(^\/)"],
styles: ["(^data:)|(^http[s]?:)|(^\/)"]
}
});
var polymer = pickFiles('bower_components/', {
srcDir: '',
files: [
'webcomponentsjs/webcomponents.js',
'polymer/polymer.js',
'polymer/polymer.html'
],
destDir: '/assets'
});
module.exports = mergeTrees([
polymerVulcanize,
polymer,
app.toTree()
]);
<!--
This file belongs at app/elements.html. Loads the polymer elements as a single file, rather than a bunch of individual link requests.
You can customize the elements loaded here if you don't need certain things or want to add your own custom elements.
-->
<link rel="import" href="../bower_components/core-elements/core-elements.html">
<link rel="import" href="../bower_components/paper-elements/paper-elements.html">
<link rel="import" href="../bower_components/paper-dialog/paper-action-dialog.html">
<link rel="import" href="../bower_components/paper-dialog/paper-dialog-transition.html">
<link rel="import" href="../bower_components/font-roboto/roboto.html">
<link rel="import" href="../bower_components/core-icons/av-icons.html">
<link rel="import" href="../bower_components/core-icons/communication-icons.html">
<link rel="import" href="../bower_components/core-icons/device-icons.html">
<link rel="import" href="../bower_components/core-icons/editor-icons.html">
<link rel="import" href="../bower_components/core-icons/hardware-icons.html">
<link rel="import" href="../bower_components/core-icons/maps-icons.html">
<link rel="import" href="../bower_components/core-icons/notification-icons.html">
<link rel="import" href="../bower_components/core-icons/social-icons.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/cascade-transition.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/core-transition-pages.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/cross-fade.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/hero-transition.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/list-cascade.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/scale-up.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/slide-down.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/slide-from-bottom.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/slide-from-right.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/slide-up.html">
<link rel="import" href="../bower_components/core-animated-pages/transitions/tile-cascade.html">
<!--
These go right below {{content-for 'head'}} in your app/index.html file
Polymer really doesn't like having other scripts loaded first (especially jQuery).
-->
<script src="assets/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="assets/vulcanized.html">
// Add these dev dependencies
"devDependencies": {
"broccoli-static-compiler": "^0.1.4",
"broccoli-merge-trees": "^0.2.0",
"broccoli-vulcanize": "^1.0.4"
}
@dnegstad
Copy link
Author

dnegstad commented Nov 6, 2014

The background work necessary to get the Polymer Web Component library working in an ember-cli app.

Some important notes:

  1. The current Ember {{bind-attr}} implementation and jQuery don't play nicely with Polymer attribute bindings AT ALL. You'll need to wrap things up in an Ember component and manage the attribute states yourself in raw JS if you need to bind to anything that a Polymer component already binds internally. You can use this.$()[0].getAttribute/setAttribute plus event bindings to pretty easily get around the issue. Once Ember 2.0 drops, you should be able to have attribute bindings play nicely right out of the box, meaning you can basically use a Polymer component as a drop in replacement for an equivalent Ember component.
  2. Things can and will break in older browsers. Sometimes in newer browsers too. Current Chrome releases are the only ones that don't need polyfills. That being said, this stuff runs surprisingly well in Safari (even on iOS) and Firefox. This is the bleeding edge and you have to decide how much risk you're comfortable with/how much pull you have in mandating what browsers your users will use. That being said, remember when sites used to only run in Internet Explorer? Making people use HTML5 standard compliant browsers to access your site/app is just karma coming back around.
  3. Polymer components may not seem that exciting at first glance, but trust me, they're super cool. Spend some time poking around their demo pages or checkout the Topeka quiz app on desktop or mobile for an example of what you can build.

@jlesquembre
Copy link

Cool article! I can now show Polymer components in my ember app, but I don't get how to bind attributes. In my case, I want to react to changes in a text input (paper-input in polymer) Do you know if that is possible?

@JHKennedy4
Copy link

As of Polymer 0.5 (https://blog.polymer-project.org/announcements/2014/10/16/platform-becomes-webcomponents/), platform/platform.js is now webcomponentsjs/webcomponents.js in both Brocfile.json and index.html.

You can see the changes in my fork https://gist.github.com/JHKennedy4/66a8468b7c5f79614396

If there's a way to submit a PR to a gist, let me know. I don't know how to do it.

@dnegstad
Copy link
Author

dnegstad commented Dec 9, 2014

@jlesquembre Direct attribute binding isn't quite there yet. With HTMLBars it works a little better, but you still need to rely on events to watch for property changes. I've been wrapping some components up in Ember components with a few observers and event handlers for more complex cases like dialog boxes.

@dnegstad
Copy link
Author

dnegstad commented Dec 9, 2014

@JHKennedy4 Just ended up upgrading to 0.5 a few days ago. Let me see about pulling in your changes so people aren't getting deprecation warnings.

@dnegstad
Copy link
Author

dnegstad commented Dec 9, 2014

Now updated for the new and improved Polymer 0.5. You'll want to update your broccoli-vulcanize to 1.0.4 or greater to get the latest vulcanize version.

@richieb
Copy link

richieb commented Dec 16, 2014

@dnegstad Could you post a gist or snippet of a working example of Polymer/Ember Components with bindings? That would certainly help. No need to refactor code or post a complete example, just drop a few lines (straight out of your project) in a reply so we can see what you have done.

@Samsinite
Copy link

@richieb, you can listen for fired events from a polymer component by adding an event listener to the element of the component.

polymer custom post-card component:

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/core-icon-button/core-icon-button.html">

<polymer-element name="post-card">
  <template>
    <style>
    :host {
      display: block;
      position: relative;
      background-color: white;
      padding: 20px;
      width: 100%;
      font-size: 1.2rem;
      font-weight: 300;
        margin-bottom: 30px;
    }
    .card-header {
      margin-bottom: 10px;
    }
    polyfill-next-selector { content: '.card-header h2'; }
    .card-header ::content h2 {
      margin: 0;
      font-size: 1.8rem;
      font-weight: 300;
    }
    polyfill-next-selector { content: '.card-header img'; }
    .card-header ::content img {
      width: 70px;
      border-radius: 50%;
      margin: 10px;
    }
    core-icon-button {
      position: absolute;
      top: 3px;
      right: 3px;
      color: #636363;
    }
    :host([favorite]) core-icon-button {
      color: #da4336;
    }
    </style>
    <div class="card-header" layout horizontal center>
      <content select="img"></content>
      <content select="h2"></content>
    </div>
    <core-icon-button id="favicon" icon="favorite" on-tap="{{favoriteTapped}}"></core-icon-button>
    <content></content>
  </template>
  <script>
    Polymer({
      favoriteTapped: function(event, detail, sender) {
        this.fire('favorite-tapped');
      }
    });
  </script>
</polymer-element>

post-card ember component (js):

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'post-card',
  post: null,

  favoriteSelected: function() {
    console.log("Post card favorited");
  },

  didInsertElement: function() {
    var element   = this.$()[0],
        avatarUrl = this.get('post.avatar'),
        self      = this;

    if (element && avatarUrl) {
      var avatarImage = element.getElementsByTagName('img')[0];

      avatarImage.setAttribute('src', avatarUrl);
      element.addEventListener('favorite-tapped', function() {
        self.favoriteSelected();
      });
    }
  }
});

post-card ember component template (handlebars):

<img width="70" height="70">
<h2>{{post.username}}</h2>
<p>{{post.text}}</p>

I'll share my ember-polymer version of the polymer starter tutorial soon.

@Samsinite
Copy link

Hope it helps. While it isn't too hard to do, figuring out how to listen to polymer events from ember took me about 3 hours to research.

@Samsinite
Copy link

I've created the ember-cli addon ember-polymer to automate this task. Thanks @dnegstad for doing the hard part :D. @richieb I put together an example of the polymer starter tutorial where use the technique mentioned above for the post-card ember component which wraps the polymer post-card component.

@richieb
Copy link

richieb commented Dec 30, 2014

Thanks a lot, @Samsinite. Your examples are very helpful. I will give them a go when I resume working on the project. I had put my Ember/Polymer project to rest for a bit.

@dnegstad
Copy link
Author

dnegstad commented Jan 4, 2015

Awesome work on setting up an addon @Samsinite! I've been too busy lately to do anything beyond throwing the examples up here.

@dnegstad
Copy link
Author

dnegstad commented Jan 4, 2015

Also, this other gist may come in handy if anyone starts seeing weird errors in browsers other than chrome when mixing Polymer and Ember.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment