Being convinced during the polymer summit by ebidel's talk to try es6 with polymer, I did try to follow his guide for creating es2015 compatible elements with Polymer.
I did notice that some of my elements weren't then executing all animations. I was able to track down the issue to this simple example:
http://jsbin.com/siqisuvelo/edit?html,console,output
Basically, any methods mixed in from a behavior are undefinied when converting the element definition to a es2015 class.
Using the es5 example, the attached() log outputs:
created from behavior called
local property from element
public behavior prop
private behavior prop
publicMethod() {}
_privateMethod() {}
However, when commenting the es5 element definition and uncommenting the class, attached now produces:
created from behavior called
local property from element
public behavior prop
private behavior prop
undefined
undefined
The 2 behaviors method are undefinied, which is why when using neon-animations behavior, I couldn't get the player animation to work.
Is there a workaround? For this reason, I can't use es6 class in my new code.
@sjmiles can you look at this? This is a reduced case: http://jsbin.com/tuqacasima/edit?html,console,output
The behavior's methods (publicMethod and _privateMethod) don't end up on the element's prototype. You'll see them print undefined.
Ok, there is a chicken-and-egg problem, because behaviors themselves want to have access to beforeRegister. We may have to add an even earlier callback. If anybody has a suggestion for naming that is aesthetic in the context of ES6 class definition, suggest away.
In the meantime, one can set up behaviors with a getter like so:
get behaviors() {
return [MyBehavior];
}
http://jsbin.com/cegepi/edit?html,console,output
This property is only accessed for preprocessing so it doesn't have the drawbacks one would have if, for example, one tried to declare properties this way.
Maybe it's not terrible if we keep beforeRegister and recommend a getter is the way to define behaviors ? I almost like that better because it'll be read-only.
It's an ergonomics thing, so I'm happy to gather feedback on what people like.
Also, what you say about being read-only makes sense.
In the meantime, I've updated our ES6 article to recommend the getter:
https://github.com/Polymer/docs/commit/8ec28d50ea5ee6414a7df64f20e0a93452e1c649
Using a behaviors instead of a property was one of my first trial when I saw that issue. It works with most of behaviors but has a weird interaction with neon-animation (maybe it's not related).
If you implement any neon-animation behavior (like Polymer.NeonAnimationRunnerBehavior), running the animation (with this.playAnimation('entry') for instance) will give you an exception (_animationMeta is undefined) on neon-animation-runner-behavior.html:42:
var animationConstructor = this._animationMeta.byKey(config.name);
meaning that Polymer.IronMeta({type: 'animation'}); returns undefined. I didn't dive deeper into it, but I guess it can be a registration order issue or an accessor that it can't get?
I am using ES6 class and whilst using _get behaviors()_ works for the simple case, there appears to be a bug when using behavior extension:
var CompositeBehavior = [BehaviorA, BehaviorB]
get behaviors(){
return [CompositeBehavior, BehaviorC]
}
In this case the composite behaviors are ignored and only BehaviorC is added to element
[CompositeBehavior, BehaviorC] works fine for es5 Polymer({}) elements
Example Plunker: http://plnkr.co/edit/fNcOznMLaNkslgtRi4qP?p=preview
@ebidel Here is the behaviors issue we discussed today.
to work around the composite behaviors I have been recommending pluralizing the names and then using a es6 spread to apply them.
e.g.
get behaviors() {
return: [ ...CompositeBehaviors, BehaviorC ]
}
The downside is knowing that a behavior is a composite and a relying on a naming scheme.
@sjmiles can you take a look?
Is it because by using the getter syntax, and therefore becoming read only, it breaks desugaring? During behavior desugar (which is what I believe flattens out all composite behaviors, correct me if I'm wrong), it attempts to override the behaviors with the updated flat list of behaviors, but would fail if only a getter is defined.
Using a setter and getter seems to patch this, though a bit messy:
get behaviors() {
return this._behaviors || (this._behaviors = [CompositeBehavior]);
}
set behaviors(value) {
this._behaviors = value;
}
See this forked plunker of @nathfisher's http://plnkr.co/edit/s0QS79MNriaemXsRex21?p=preview
Benefit of this over using the spread syntax is that it should flatten out nested arrays, and work with 3rd party behaviors such as NeonAnimation
@sjmiles @ebidel any updates on this one?
It would be nice if this were documented on the official behaviors documentation page
I've created a pull request.
If it helps anyone, I'm using this to get around this issue:
Somewhere globally:
const flatten = a => a.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
Polymer.behaviors = Polymer.behaviors || {};
Polymer.behaviors.get = behaviors => flatten(behaviors);
Then in my elements:
get behaviors () {
return Polymer.behaviors.get(MyBehaviorOne);
}
Or:
get behaviors () {
return Polymer.behaviors.get([MyBehaviorOne, MyBehaviorTwo]));
}
@ebidel @sorvell @kevinpschaaf is there a recommended workaround for the issue described here https://github.com/Polymer/polymer/issues/2451#issuecomment-157891621? Or a fix?
Does https://github.com/Polymer/polymer/issues/2451#issuecomment-224083145 work (or the other workarounds)? To fix this properly, someone from core needs to take a look.
I've also come into an issue where a behavior that has a read-only property and a method that sets it via _setMyProperty does not actually work when it is used in an es6 class component.
Its defined just as outline using the get behaviors() { return [myBehavior] } but console errors as
this._setMyProperty is not a function.
Sorry for the lack of communication after the multiple pings 😢 . I am going through the issues now to find these kind of issues. As we are now in Polymer 2 land, this issue should be resolved by using Polymer.mixinBehaviors, see http://jsbin.com/jadavaz/1/edit?html,console,output
Most helpful comment
@sjmiles @ebidel any updates on this one?