7

I have a set of custom polymer elements, that I would like to use within an angular 2 application.

It seems like there's a problem concerning the content tag of the polymer element. The content of the element gets rendered at the wrong place within the polymer element, if the element is located within an angular 2 component.

Example:

The template of my polymer element "my-button" looks like this:

<template>

  <button>
    <content></content>
  </button>

</template>

Use outside angular

When I use this element outside of my angular 2 component, I get the result that I expected:

Use:

<my-button>Foo</my-button>

Result:

<my-button>
  <button>
    Foo
  </button>
<my-button>

Use within angular 2 component

When used within an angular 2 component, the content always gets rendered at the end of the elements template. Just like the content tag didn't exist.

Use:

<my-button>Foo</my-button>

Result:

<my-button>
  <button>

  </button>
  "Foo"
<my-button>

Question

The problem might be, that polymer and angular 2 both use the content tag for transclution. So maybe things get a little messy when using both together.

I would love to use all of my polymer elements inside angular 2. So any ideas on how to fix this would be very much appreciated.

Simon
  • 296
  • 4
  • 17

2 Answers2

8

There are a few open issue about Angular2 combined with Polymer. For example Angular doesn't use Polymer.dom(el)... for manipulating a Polymer elements children. This is probably what breaks your components. A workaround is to enable full shadow DOM and polyfills. See https://www.polymer-project.org/1.0/docs/devguide/settings.html

An issue I haven't found a solution yet is passing <template>s (like required for example for <iron-list>. Angular handles templates on its own and doesn't pass it to the Polymer element.

There is a ngNonBindable directive. I haven't tried it yet on the <template ngNonBindable> myself but it might work. I tried it seems that's only to ignore [prop]="field"/prop="{{field}} bindings.

Another issue is with <style is="custom-style">. They can only be added in the <head> element or within Polymer elements, but not to Angular components.

See also Two-way binding in Angular 2 with NgModel and mutating bound property?

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • ive been trying polymer components, take for example the paper-checkbox, now if i bind the property checked `[checked]="myselection"` it simple sets the boolean but does not get if checked? Is there any explanation why these elements behave in such way? PS i have enabled dom = 'shady' – Pratik Kelwalkar May 09 '16 at 09:16
  • @PratikKelwalkar Polymer with shady DOM doesn't work well with Angular2. I suggest enabling shadow DOM instead. Not sure what you mean by "but does not get if checked". You would need `[checked]="myselection" (checkedChanged)="myselection = $event"` (not tested myself) – Günter Zöchbauer May 09 '16 at 09:19
  • Ok thanks zoechi,il try out, what I wanted was to find out if the check box was checked using the attribute [checked], but I wasn't able to get the boolean, instead only was able to set the value. – Pratik Kelwalkar May 09 '16 at 09:22
  • 1
    `[checked]=...` in Angular2 is only binding from model to view. `(xxx)` is binding from view to model. This works for properties of Polymer elements that notify. In Angular there is `[(xxx)]="..."` for two-way binding but that requires some naming convention that is violated by Polymer because it fires notification events like `checked-changed` while Angular requires `checkedChange` for two-way binding to work. http://stackoverflow.com/questions/35867952/how-to-use-angular2-ngmodel-for-polymer-paper-input-error-no-value-accessor-fo for an alternative way (not tried with paper-checkbox) – Günter Zöchbauer May 09 '16 at 09:28
  • `[checked]="myselection" (checkedChanged)="myselection = $event"` doesnt work, any suggestion how it might work. Im able to get the checked value through `@ViewChild()` but that isnt exactly what i want. I want to use this in ngForm, where the ngModel binding must work....any suggestions how to do this. – Pratik Kelwalkar May 09 '16 at 09:43
  • Please try `(checked-changed)` instead of `(checkedChanged)` – Günter Zöchbauer May 09 '16 at 09:47
  • It suprises me, well the polymer documentation states it notifies, then shouldnt [] bindings value change? Lets take another example https://elements.polymer-project.org/elements/google-signin#property-isAuthorized here the signedIn attribute cannot be binded, meaning i cannot get data from view to model? – Pratik Kelwalkar May 09 '16 at 10:32
  • 1
    Angulars `[...]` doesn't do 2-way binding and `[(...)]` only when the naming convention is fulfilled. For the component you linked to, you can use `(google-signin-success)="loggedIn = $event.detail.value"` https://elements.polymer-project.org/elements/google-signin#event-google-signin-success – Günter Zöchbauer May 09 '16 at 10:40
  • 1
    That's another one I messed up above. `[checked]="myselection" (checkedChanged)="myselection = $event.detail.value"` because in Polymer the event is in `detail.value` while in Angular the event itself is the value. You perhaps need to investigate per event because not each Polymer event provides a `value` or might also provide different properties. – Günter Zöchbauer May 09 '16 at 10:41
7

Check out https://www.npmjs.com/package/@vaadin/angular2-polymer, which should resolve most issues in integrating Polymer elements to Angular 2.

User guide: https://github.com/vaadin/vaadin-core-elements/blob/master/docs/angular2.adoc

Tutorial (draft): https://github.com/vaadin/angular2-polymer/blob/d4581e8fd82841eea84ef40e16e262a12ee4b082/docs/tutorial.adoc

Better shady DOM support is waiting to be merged from a separate branch (should be merged and released within two weeks): https://github.com/vaadin/angular2-polymer/tree/feature/polymer-dom-adapter

It would be great if you could try it out and see if it works for you!

Eventually, the documentation will be published at https://vaadin.com/docs/

Jouni
  • 2,830
  • 15
  • 12