angular-polymer
angular-polymer copied to clipboard
Ahead of Time (AoT) compile doesn't work with PolymerElement in declarations
When using PolymerElement function inside the @NgModule, the AoT compiles complains with the following message:
Error encountered resolving symbol values statically. Calling function 'PolymerElement', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function
@NgModule({
...
declarations: [
PolymerElement('paper-input') //This is what doesn't work with AoT
],
...
})
Solutions to this error message have been provided in:
But almost all use the useFactory attribute as a workaround, but, declarations don't have such a feature.
Hello,
Same problem here:
Error: Error encountered resolving symbol values statically. Calling function 'PolymerElement', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function
Any solution? Thanks
It would be really good to know if there is an alternative that will be provided
I get the same message like @DanielGarciaMandillo As far as i understood the i18n of ng2, AOT will be required to compile apps with multiple languages.
I spent the last couple of days playing with this, and the only way that I could come up with was to generate source code for each element ahead of time.
For instance, write a base class that looks something like this: export class ChangeEventsAdapterDirective {
protected _eventNameForProperty = (property: string) => `${property}Change`;
constructor(props: string[]) {
props
.forEach(property => this[property] = new EventEmitter<any>(false));
}
_emitChangeEvent(property: string, event: any) {
// Event is a notification for a sub-property when `path` exists and the
// event.detail.value holds a value for a sub-property.
// For sub-property changes we don't need to explicitly emit events,
// since all interested parties are bound to the same object and Angular
// takes care of updating sub-property bindings on changes.
if (!event.detail.path) {
this[this._eventNameForProperty(property)].emit(event.detail.value);
}
}
}
And then add an implementation for each element, along these lines:
@Directive({ selector: 'paper-tabs', host: { '(selected-changed)': '_emitChangeEvent("selected", $event)', '(selected-item-changed)': '_emitChangeEvent("selectedItem", $event)', '(items-changed)': '_emitChangeEvent("items", $event)', '(selected-values-changed)': '_emitChangeEvent("selectedValues", $event)', '(selected-items-changed)': '_emitChangeEvent("selectedItems", $event)' } }) export class PaperTabsChangeEventsAdapterDirective extends ChangeEventsAdapterDirective { @Output() selectedChange: any; @Output() selectedItemChange: any; @Output() itemsChange: any; @Output() selectedValuesChange: any; @Output() selectedItemsChange: any;
constructor() {
super(['selectedChange', 'selectedItemChange', 'itemsChange', 'selectedValuesChange', 'selectedItemsChange']);
}
}
I did this for all of the elements in my project, and they all seem to work, but it's definitely a hassle. I don't know of a cleaner way to manage it at this point though.
@dcoblentz Had a similar thought but didn't want to go down that route. Awesome work on your part. If this is the only way to achieve this for now, what do you think about creating a separate repo and sharing the definitions that you have and we could collaborate to bring all paperElements into it
I think AoT is essential with Angular 2. The 2+ sec parse time (which seems to be 10 sec on a tablet) just really not lives up to the promise of Angular 2. On the other hand, Material 2 will be soon there where Polymer elements are now (IMHO). So it is a good question if this is worth the effort. Do you guys think that it is of added value to maintain Polymer Angular 2 bridge in the long term? If so, what are your reasons?
@istvanszoboszlai
- AOT is a must have when dealing with i18n in angular2
- I don't think Material 2 will be comming "soon" when I take a look at their roadmap
- The Angular Material 1 Datepicker was crap, I don't really trust them for V2.
- Material 2 has no file upload component in their roadmap
- Since the first day of Material 1 they promise a grid, but they have never delivered one
- Their IE support was never really good. Somehow I don't trust them here too.
- The vaadin web components are awesome. :-)
So yes, please continue this. At least until Material 2 will maybe become mature.
One thing to note about dcoblentz solution, it does enable two way data binding. But, it will require shadow dom fully enabled if you want to use components with content/slot. For example, using shady dom, something like:
<paper-input><span suffix>$</span></paper-input>
Won't work, because of the Polymer.dom dependency on web components with shady dom (As far as I saw, it won't be required on Polymer 2 as it uses dom functions directly). Angular2-Polymer solves this with the classes PolymerShadyDomAdapter: https://github.com/vaadin/angular2-polymer/blob/master/src/polymer-element.ts#L27
Or, have you find any solution that doesn't require that class or shadow dom fully enabled?
@rstpv I believe we could still continue to use a combination of both. The solution provided by @dcoblentz makes the directive declarations for each component static(which is required for AOT to work). We could still use the PolymerShadyDomAdapter provided by angular2-polymer as it is not directly linked to the creation of the directives but rather sets the Root DOM Adapter.
This is pretty rough, but here's a gist with the code I wrote, it's all pretty rough still, but I copied the output from my browser console to a new ts file, but it would of course be better to turn it into a cli tool that can generate each file directly.
https://gist.github.com/dcoblentz/b16e97bc5671a8c31ab65add8c88b041
We’re going to do a quick round of prototyping (2d timebox) to get a better understanding about this, what would be a viable fix for this issue.
Best news today so far :)
@dcoblentz, this is really awesome what you did. I do not get the whole process, however. How do you generate output.ts? Can this be applied to vaadin polymer elements, too?
We finished our research. Highlights below. Currently https://github.com/vaadin/angular2-polymer/issues/104 is prioritized as the next fix in the future, but after that AoT support will probably be the next one. ETA 2017Q1.
Problem
When following the Angular’s AoT guide (https://angular.io/docs/ts/latest/cookbook/aot-compiler.html) the development with angular2-polymer will fail when trying to compile the application.
You can reproduce the issue in angular2-polymer-quickstart AoT branch: https://github.com/vaadin/angular2-polymer-quickstart/tree/aot
Error: Error encountered resolving symbol values statically. Calling function 'PolymerElement', function calls are not supported.
Cause of Problem
Feature in Angular: https://github.com/angular/angular/blob/491d5a22a9dc1082e80aa5ca481aa02b49b9bfe8/modules/%40angular/compiler/src/aot/static_reflector.ts#L695 The reason for this limitation is that the AoT compiler needs to generate the code that calls the factory and there is no way to import a lambda from a module and you can only import an exported symbol. Meaning you can’t call functions in metadata. Code should be statically analyzable.
Possible Solutions
- Extend useFactory: https://github.com/angular/angular/issues/10789#issuecomment-242220591
- Generate Source Codes for each element: https://github.com/vaadin/angular2-polymer/issues/86#issuecomment-255398864
- CLI-tool to generate source code for each element
if some one needs, I used polymer-element.ts to implement a class for directives generation, it is not a CLI-tool, but generates directives for a component, I hope helps you:
polymer-directive-generator.ts https://gist.github.com/axtlotic/06f8715a6ea0223af6fbd6cbf1266be7
app.component.ts https://gist.github.com/axtlotic/36764dc3747526aaa6254b39dc78a106
app.component.html https://gist.github.com/axtlotic/8ada0ade7244b412190a1d66e4c4abac
app.component.css https://gist.github.com/axtlotic/1113f933aee2a5e588161d6a8d0797e8
app.module.ts (example) https://gist.github.com/axtlotic/fddb1527f861c8fe8ad626d5bf3ff440
@axtlotic Could this be used to create a pre-built public package for all elements?
Any ideas when this will be fixed?
@mpartipilo thanks, if this is possible, I would have to install all the elements in my project and modify it to generate the directives, I hope to get the complete list of elements and give me some time to do it
@axtlotic Thanks for the generator. but when I use the generated code in my component. the ng build gave me this message:
chunk {0} main.bundle.js, main.bundle.map (main) 26.1 kB {2} [initial] [rendered] chunk {1} styles.bundle.js, styles.bundle.map (styles) 9.99 kB {3} [initial] [rendered] chunk {2} vendor.bundle.js, vendor.bundle.map (vendor) 2 MB [initial] [rendered] chunk {3} inline.bundle.js, inline.bundle.map (inline) 0 bytes [entry] [rendered]
ERROR in ./src/app/app.component.ts Module not found: Error: Can't resolve 'app.component.html' in '/Users/xukai/git/angular2/my-project/src/app' @ ./src/app/app.component.ts 21:22-51 @ ./src/app/index.ts @ ./src/main.ts @ multi main
ERROR in ./src/app/app.component.ts Module not found: Error: Can't resolve 'app.component.css' in '/Users/xukai/git/angular2/my-project/src/app' @ ./src/app/app.component.ts 22:21-49 @ ./src/app/index.ts @ ./src/main.ts @ multi main
what have I missed?
my module is like this:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { PolymerElement } from '@vaadin/angular2-polymer';
import { AppComponent } from './app.component';
import { PaperInput } from './paper-input-directives';
import { VaadinComboBox } from './vaadin-combo-box-directives';
@NgModule({
declarations: [
AppComponent,
PaperInput,
VaadinComboBox
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [],
entryComponents: [AppComponent],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
and my **component **
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
})
export class AppComponent {
title = 'app works!';
myLabel = 'Select a number';
myValue = '4';
myItems = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
}
and my template
<h1>{{title}}</h1>
<h2>{{title}}</h2>
<vaadin-combo-box [label]="myLabel" [(value)]="myValue" [items]="myItems"></vaadin-combo-box>
<paper-input [(value)]="myValue"></paper-input>
@axtlotic ok that was a path mistake I solved it by change templateUrl: 'app.component.html', styleUrls: ['app.component.css'], to templateUrl: './app.component.html', styleUrls: ['./app.component.css'],
thank you for your generator , it's good enough for me now.
How to use this generator? How to implement this solution?
@tomaszcysewski I created a generator project in Github here: https://github.com/hydraslay/ng2-polymer-static-gen And use the generated xxx.directives.ts file just like this project: https://github.com/hydraslay/ng2-polymer-static
There is still something need to be adjusted in vaadin-date-picker and vaadin-grid while other paper-xxx works well.
Those are most used elements I think. I want to install this in order to use vaadin-grid. Let's make a request for this adjusting, who develop this generator generally?
Unfortunately it is not working every time. If I am using a paper-dialog which has a vaadin-date-picker the dialog will not open. If I delete the containing vaadin-date-picker the dialog is working again. The vaadin-date-picker is working, but not with the dialog.
And I have some problems with paper-input in the paper-dialog. They do not show their actual value.
Do you may have some suggestions?
Already turn to another UI Component "PrimeNG" because the commercial project won't wait. But the primeNG is not a material design, sad. And the same time, keeping another eye on the schedule of material2. This is the thing I really want.
AOT is available (but first you should generated static directives). Check this repository
sounds like I have done twice AOT compile, One for Polymer, One for Angular...
@hydraslay thanks for sharing your solution. Yeah, looks like we can’t avoid some generation step for Polymer in general.
My idea on this — to try making a nicer generator using the polymer-analyzer output, so that you don’t have to run the browser with elements and copy the generated directives code. This can be well automated, I believe. Prototyping this idea nowadays.
I would avoid publishing the generated directives, however, because then updating them for all the changes in all the elements is likely to turn into a big maintenance problem.