Polymer 3 "Uncaught ReferenceError: Polymer is not defined" - polymer

I am new to polymer and I have the following problem after running "polymer build" and when I run "polymer serve build / esm-bundled" the following error occurs in the browser:
Uncaught ReferenceError: Polymer is not defined
I noticed that if I disable the polymer.json's bundle the error does not appear.
Can someone help me please?
I'm using Polymer-3 and Redux, this project was built initially with the polymer-2, but I did the conversion and it works fine when I run before the build.
This is polymer.json
{
"entrypoint": "index.html",
"shell": "src/components/conversion-today-app/conversion-today-app.js",
"sources": [
"src/**/*",
"images/**/*",
"robots.txt",
"sitemap.xml",
"coinzilla-354635a9db1dbd05d0.txt"
],
"extraDependencies": [
"manifest.json",
"node_modules/web-animations-js/**",
"node_modules/#webcomponents/webcomponentsjs/**",
"node_modules/#polymer/polymer/**"
],
"builds": [
{
"name": "esm-bundled",
"browserCapabilities": [
"es2015",
"modules"
],
"js": {
"minify": true
},
"css": {
"minify": true
},
"html": {
"minify": true
},
"bundle": true,
"addServiceWorker": true
}
]
}
Part of the component where the error is
// Principais // Bibliotecas
import { PolymerElement,html } from '#polymer/polymer/polymer-element.js';
// import { html } from '#polymer/polymer/lib/utils/html-tag.js';
import { afterNextRender } from '#polymer/polymer/lib/utils/render-status.js';
import { connect } from 'pwa-helpers/connect-mixin.js';
// pwa helper
import { installOfflineWatcher } from 'pwa-helpers/network.js';
// ---------- Redux ----------
// This element is connected to the redux store.
import { store } from '../../store.js';
// These are the actions needed by this element.
import { addCoin } from '../../actions/converter.js';
import converter from '../../reducers/converter.js';
import { fetchCrypto } from '../../actions/cryptoCoins.js';
import { fetchCurrencyState } from '../../actions/stateCoins.js';
// We are lazy loading its reducer.
import cryptoCoins from '../../reducers/cryptoCoins.js';
import stateCoins from '../../reducers/stateCoins.js';
store.addReducers({
stateCoins, cryptoCoins
});
// Componentes de Terceiros
import '#polymer/paper-fab/paper-fab.js';
import '#polymer/paper-dialog/paper-dialog.js';
import '#polymer/paper-dropdown-menu/paper-dropdown-menu-light.js';
import '#polymer/paper-dropdown-menu/paper-dropdown-menu.js';
import '#polymer/paper-button/paper-button.js';
import '#polymer/iron-demo-helpers/demo-snippet.js';
import '#polymer/iron-demo-helpers/demo-pages-shared-styles.js';
import '#polymer/paper-item/paper-item.js';
import '#polymer/paper-listbox/paper-listbox.js';
import '#polymer/iron-ajax/iron-ajax.js';
import '#polymer/app-storage/app-localstorage/app-localstorage-document.js';
// Components locais
import '../elements/collection-coin-element.js';
class ConversionTodayConverter extends connect(store)(PolymerElement) {
static get template() {
return html`
<style include="demo-pages-shared-styles">
:host {
display: block;
padding: 10px;
}
paper-fab {
--paper-fab-background: #2B4461;
display: inline-block;
/* margin: 8px; */
position: fixed;
right: 25px;
bottom: 30px;
}
</style>
<app-localstorage-document key="conversion-today-coins" data="{{coins}}">
</app-localstorage-document>
Browser -- error
This is what appears in the browser

First of all: You should add some code examples of your elements, since it it's not easy to solve your problem without any further informations 😉
When I upgraded my projects to polymer 3.x I always got that console error when I forgot to replace usages of the legacy Polymer class. For example: In Polymer-2 an element was defined by class XCustom extends Polymer.Element {...} but in polymer-3 it is class XCustom extends PolymerElement {...}. If you forget to change that in any element (your own and the imported ones), your console with throw the Polymer is not defined-error.
So I guess in your Webapp/Element there are still references to the legacy Polymer-class. In my case it was mostly on of these usages: Polymer.Element, Polymer.importHref(...) or Polymer.mixinBehaviors(...). You should simple search your project files for the usage of "Polymer." and replace all occurrences with the equivalent polymer-3-functions.
Here are some of the most common upgrade replacements in polymer-3:
Polymer.Element
Create an element as follows:
import { PolymerElement, html } from '#polymer/polymer/polymer-element.js';
class MyElement extends PolymerElement {...}
Also have a look at the Polymer docs
Polymer.mixinBehaviors(...)
Use behavior mixins as follows:
import {IronResizableBehavior} from '#polymer/iron-resizable-behavior/iron-resizable-behavior.js';
import { mixinBehaviors } from '#polymer/polymer/lib/legacy/class.js';
class MyElement extends mixinBehaviors([IronResizableBehavior],PolymerElement) {...}
Polymer.importHref(...)
Import elements as follows:
import('./my-page.js').then(
function(){
console.info("Success");
}.bind(this),
function(){
console.info("Fail");
}.bind(this)
);
Also have a look at the Polymer docs

Related

Only in the context of a <Router> component error on import outside project root

I have two React projects.
Project "app" contains the main project.
Project "sb" contains a Storybook project.
The dependencies have been made the same, both projects are created with CRA.
app/
components/
SampleComp.tsx
sb/
components/
SampleComp.tsx
stories/
SampleComp.stories.tsx
Both SampleComp.tsx are exactly the same in code.
When I import SampleComp.tsx from the sb/components folder, it's working.
When I import SampleComp.tsx from the app/components folder, it's NOT working.
The latter fails with the following error in Storybook:
"useHref() may be used only in the context of a component."
In the stories, I wrap the component in the MemoryRouter.
SampleComp.tsx (both)
import React from "react";
import { Link } from "react-router-dom";
export function SampleComp() {
return (
<div>
Home page
<Link to="/test">Test</Link>
</div>
);
}
SampleComp.stories.tsx
import React from "react";
import { ComponentStory, ComponentMeta } from "#storybook/react";
// import { SampleComp } from "../../app/components/SampleComp"; // not working
import { SampleComp } from "../components/SampleComp"; // works!
import { MemoryRouter } from "react-router";
export default {
title: "SampleComp",
component: SampleComp,
parameters: {
layout: "fullscreen",
},
} as ComponentMeta<typeof SampleComp>;
const Template: ComponentStory<typeof SampleComp> = (args) => (
<MemoryRouter>
<SampleComp />
</MemoryRouter>
);
export const Default = Template.bind({});
Why doesn't it work the same?

Exclude JSON files from the main bundle with webpack for react-lottie

In our web app we have a few JSON files that are ~10-80k lines each. These are getting included in our main bundle. These are used by an animation plugin called react-lottie.
An example of our webpack.config.js
module.exports = {
entry: ["./src/index.js"],
module: {
rules: [
{ test: /\.(js|jsx)$/, exclude: /node_modules/, use: ["babel-loader"] },
{
test: /\.(jpg|png|gif|ico)$/,
use: {
loader: "file-loader",
options: { name: "[path][name].[hash].[ext]" }
}
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
output: {
path: __dirname + "/dist",
publicPath: "/",
filename: "[name].[hash].js"
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ hash: false, template: "src/index.html" }),
new DashboardPlugin(),
new CopyWebpackPlugin([
{
from: "src/components/Assets/BookingBar.js",
to: "assets/BookingBar.js"
}
]),
new BundleAnalyzerPlugin()
],
devServer: {
contentBase: "./dist",
hot: true,
historyApiFallback: true,
port: 4000
}
};
What is the expected behavior?
There should be a way to exclude .json files from the main bundle. I've tried File-Loader, json-loader, and const someJson = require(./someJson)
Other relevant information:
webpack version: 4.16.1
Node.js version: 10.12.0
Operating System: Mac OS 10.14 Mojave
ANSWER BELOW (AT LEAST FOR HOW I SOLVED IT). I couldn't initialize the lottie without any data.
The expected behavior is that the JSON will get bundled because it's, presumably, needed synchronously at runtime. JSON data differs from something like image files which are loaded asynchronously by the browser as they are rendered on the page via src attributes etc.
As the comments mentioned, you should be using code splitting. The latest version of Webpack supports dynamic imports if you install and use the #babel/plugin-syntax-dynamic-import plugin.
npm install --save-dev #babel/plugin-syntax-dynamic-import
Then in babel.config.js:
module.exports = {
...
plugins: [
"#babel/plugin-syntax-dynamic-import"
]
...
};
Example
Say you have a React component that might need some JSON data, but doesn't need to load it synchronously as part of the bundle. Your non-code splitted version might look something like this:
import React from 'react';
import myJSON from './myJSON.json';
export default class MyComponent extends React.Component {
render() {
return <div>{JSON.stringify(myJSON, null, 2)}</div>
}
}
Instead you can use a dynamic import - basically a runtime import that returns a Promise you can use to asynchronously load some data chunked separately from your bundle:
import React from 'react';
import myJSON from './myJSON.json';
export default class MyComponent extends React.Component {
state = {data: {}};
componentDidMount() {
import(/* webpackChunkName: 'myJSON' */ './myJSON.json')
.then((data) => {
this.setState({data});
});
}
render() {
return <div>{JSON.stringify(this.state.data, null, 2)}</div>
}
}
Alternately, you can use React's new lazy and Suspense API (v16.6.0 and higher) to dynamically import React components that get chunked separately from the bundle. This might be preferable if you want to chunk a component and its corresponding JSON data together, but separately from the main bundle:
// MyComponent.jsx
import React from 'react';
import myJSON from './myJSON.json';
export default class MyComponent extends React.Component {
render() {
return <div>{JSON.stringify(myJSON, null, 2)}</div>
}
}
// SomeParent.jsx
import React, {lazy, Suspense} from 'react';
const MyComponent = lazy(() => import(/* webpackChunkName: 'MyComponent' */ './MyComponent'));
export default class SomeParent extends React.Component {
render() {
return <div>
<Suspense fallback={<div>Loading...<div>} >
<MyComponent />
</Suspense>
</div>;
}
}
In the above example, <MyComponent /> and its corresponding code -- including the JSON data -- will only be loaded when the component is actually rendered at runtime.
Ultimately I took the answer above below me but wasn't able to initialize the lottie without any JSON data. I ended up doing this:
import React, { PureComponent } from "react"
import Lottie from 'react-lottie'
export default class AnimationAutomatedCommunication extends PureComponent {
constructor(props) {
super(props)
this.state = {
animation: <div />
}
}
async componentDidMount() {
const animation = await import(/* webpackChunkName: "AnimationAutomatedCommunication" */ './JsonData/AnimationAutomatedCommunication.json')
const defaultOptions = {
loop: true,
autoplay: true,
animationData: animation.default
}
this.setState({
animation: <div className={this.props.className}>
<Lottie key="lottie-win-jobs" options={defaultOptions}
isStopped={this.props.isStopped} />
</div>
})
}
render() {
return (
<React.Fragment>
{this.state.animation}
</React.Fragment>
)
}
}

How to use environment variable in index.html for Angular 6

I am using angular6, in my project I am using Facebook Account Toolkit for mobile verification purpose.
I need to initialise Account toolkit in index.html file using following code.
AccountKit.init({
appId:"XX",
state:"xx",
version:"v1.2",
fbAppEventsEnabled:true,
debug:true
});
The problem is, values for appId and state change depending on environment (development/test/production).
How can I use environment variables in index.html file.
Please let me know if anyone has a solution for angular 6.
You should create copy of index.html and name it index.someenv.html.
Then in your angular.json in environment configuration setup file replacement:
"fileReplacements": [
{
"replace": "src/index.html",
"with": "src/index.someenv.html"
}
]
The angular cli will replace these files when you run your build
This answer supersedes Artyom's answer for Angular 8 and above. Add the following to your angular.json:
"production": {
"index": {
"input": "src/index.someenv.html",
"output": "index.html"
},
},
An example here for document.write(environment.variable) :
https://github.com/angular/angular-cli/issues/4451#issuecomment-285026543
import { environment } from './environments/environment';
if (environment.production) {
document.write('<script type="text/javascript">// ProductionAnalyticsCodeHere</script>');
} else if (environment.staging) {
document.write('<script type="text/javascript">// StagingAnalyticsCodeHere</script>');
}
In main.ts file you can use document.write(environment.variable) and it will write what you want in index.html
(I use it to make the Google Analytics script take a dynamic Tracking ID wether it's in development or production mode, and it works well in Angular6)
for me above answers did not work on Angular 10, so I created different folder for staging, production etc and placed the index.html which was used by CLI as per the build environment
{
"projects": {
"yourApp": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"index": "src/index.html",
},
"configurations": {
"production": {
"index": "src/production/index.html",
}
}
}
}
}
}
}
Avoid direct access to the document object by injecting DOCUMENT to your AppComponent.
import { DOCUMENT } from '#angular/common';
...
public constructor(
#Inject(DOCUMENT) private doc: any
) {
Add the tag in ngOnInit()
ngOnInit() {
this.setYourScriptTag();
}
private function to set it
private setYourScriptTag() {
const s = this.doc.createElement('script');
s.type = 'text/javascript';
s.innerHTML = `AccountKit.init({
appId: "${environment.appId}",
state: "${environment.state}",
version:"v1.2",
fbAppEventsEnabled:true,
debug:true
});`;
const head = this.doc.getElementsByTagName('head')[0];
head.appendChild(s);
}
This answer is from edodusi
https://github.com/angular/angular-cli/issues/4451#issuecomment-384992203
I think you can do it all in main.ts
const env = environment;
AccountKit.init({
appId:env.appId, // this lane
state:env.state, // this lane
version:"v1.2",
fbAppEventsEnabled:true,
debug:true
});
Thanks.
I added this in main.ts:
var html = document.documentElement.innerHTML
document.documentElement.innerHTML = html.replace("Replace me!", environment.variable)
Note that the old value will still exist in index.html for some time while the page is initially loading. (For example, use this to replace the page title and you'll see the old value displayed before the replace happens.)
import your environment file into .ts file.
import { environment } from '../../environments/environment';
Create required fields in your class, assign values from environment to these variables in the constructor, use usual binding in the .html file.
.ts
import { Component } from '#angular/core';
import { environment } from '../environments/environment';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public production = true;
constructor() {
this.production = environment.production;
}
}
.html
<span>{{production}}</span>

Are global variables accessible in Angular 2 html template directly?

So I put in app.settings like
public static get DateFormat(): string { return 'MM/DD/YYYY';}
and then in one of my html template of a component I want to do something like this.
<input [(ngModel)]="Holiday" [date-format]="AppSettings.DateFormat"/>
In component I have
import { AppSettings } from '../../../app.settings';
Right now it's not accessible like this in html template. Is there any way?
No, the scope for code in the template is the component instance. You need to assign the value to a field in the component, or add a getter or method that forwards to the global variable in order to be able to use it from the template.
import { AppSettings } from '../../../app.settings';
...
export class MyComponent {
get dateFormat() {
return AppSettings.DateFormat;
}
}
then you can use it like
<input [(ngModel)]="Holiday" [date-format]="dateFormat"/>
It seems hacky but you can use pipe. It saves you from repeating injection or variable binding for each component.
#Pipe({
name: 'settings',
})
export class GlobalVariablePipe implements PipeTransform {
transform(value: any): object {
return AppSettings;
}
}
Then, once imported in your module, you can simply use the pipe as follows:
{{(''|settings).DateFormat}}
To the best of my knowledge, no, and that's by design. Templates are hooked up in conjunction with components, that's how they derive their scope and thereby access to bindable data. It's possible it could be hacked around, but even if you figure it out, this is a path you should not follow.
I do this sort of thing with a class:
class AppConfig {}
AppConfig.Globals = {
TEST_VAL: 'hey now here is the value'
};
export { AppConfig }
And then use it like so:
import { Component } from '#angular/core';
import { AppConfig } from '../../app/app.config';
class HomeComponent {
constructor() {
this.test_val = AppConfig.Globals.TEST_VAL;
}
}
HomeComponent.annotations = [
new Component ( {
templateUrl: './views/home/home.component.html'
} )
];
export { HomeComponent }
In the template:
{{test_val}}
Works well for me.
It seems an old topic. However here is my 2 cents. I used a service instead and it's working. I come up with something like this : <input [(ngModel)]="Holiday" [date-format]="appSettingService.DateFormat"/>. The inconvenient of this solution, you have DI the service.
Here is what I did :
appSettingService.ts
import { Injectable } from '#angular/core';
#Injectable({
})
export class AppSettingService{
constructor() { }
public DateFormat(): string { return 'MM/DD/YYYY';}
...
In your component :
...
constructor(public appSettingService : AppSettingService ) { }
...
And finally your in your template:
<input [(ngModel)]="Holiday" [date-format]="appSettingService.DateFormat"/>
I'm looking for a way to use the value without the suffixe like this:
<input [(ngModel)]="Holiday" [date-format]="DateFormat"/>
Step 1. Define global json globals.json
{
"LABEL": "Your Text"
}
Step 2. Define Injectable Globals class globals.ts and add to providers in app.module.ts
import { Injectable } from '#angular/core';
import jsonGlobals from './globals.json';
#Injectable()
export class Globals {
prop: any = jsonGlobals;
}
in app.module.ts
providers: [Globals]
Step 3. Inject in component's constructor
constructor(public globals: Globals) { }
Step 4. Add following compiler properties in tsconfig.json
"resolveJsonModule": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
Step 5. Use in HTML templates
{{globals.prop.LABEL}}

Ng2-table not working with latest Angular2 version

I am currently using Angular2 for my application and now I want to add ng2-table to my component.
ng2-Table on Git
I am getting this error and couldn't help but ask:
angular2-polyfills.js:487 Unhandled Promise rejection: Template parse errors:
Can't bind to 'colums' since it isn't a known property of 'ng-table'.
1. If 'ng-table' is an Angular component and it has 'colums' input, then
verify that it is part of this module.
2. If 'ng-table' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA"
to the '#NgModule.schema' of this component to suppress this message.
("
</div>-->
<ng-table [ERROR ->][colums]="columns" [rows]="rows" > </ng-table>
<div class="">
"): DeviceOverviewComponent#18:10 ;
Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:(…)
In my html I got this:
<ng-table [columns]="columns" [rows]="rows" > </ng-table>
My Component is this:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { DeviceService } from '../services/device.service';
#Component({
selector: 'device-overview',
templateUrl: 'dist/html/deviceoverview.component.html',
providers: [DeviceService],
})
export class DeviceOverviewComponent {
devices: any;
columns: any;
rows: any;
constructor(private deviceService: DeviceService, private router: Router) {
}
loadDevices() {
this.deviceService.getDevices()
.then((data) => {
this.devices = data
this.rows = this.devices
})
}
goToDevice(deviceName: string) {
this.router.navigateByUrl('/devices/' + deviceName)
}
ngOnInit() {
this.columns = [
{ title: "test", name: "id" }]
this.loadDevices();
}
}
And my app.module is this:
import { NgModule } from '#angular/core';
import { LocationStrategy, HashLocationStrategy } from '#angular/common';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { Ng2TableModule } from 'ng2-table/ng2-table';
import { AppComponent } from './components/app.component';
import { DeviceOverviewComponent } from './components/deviceoverview.component'
import { DeviceService } from './services/device.service';
import { routing } from './app.routing';
#NgModule({
imports: [
Ng2TableModule,
BrowserModule,
FormsModule,
HttpModule,
routing,
],
declarations: [
DeviceOverviewComponent,
AppComponent,
],
providers:
[
{provide: LocationStrategy, useClass: HashLocationStrategy},
DeviceService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Does anybody know anything about the Usage of ng2-table? Or is there a valid alternative, since the demo page/usage documentation is not available by now?
I found some alternatives, but lots of them had their last commit a long time ago, which might be a problem, since I am always using latest Angular2.
Thanks for reading and any hel is appreciated!
EDIT:
I've made it to the next step!
I needed to add
import {CUSTOM_ELEMENTS_SCHEMA} from '#angular/core'
#NgModule({ ...,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
within my app.module.ts
Now I am getting the table header with the "test" column and the ID property of my row data is displayed correctly.
Even the demo from ng2-table didn't have that import.
I guess docs and demos arent made for newbes nowadays. :/
i see a typo in your html:
[colums]="columns"
It should be
[columns]="columns"
You're missing n
Plunker Example (I also tried it on local machine and it works)
You shouldn't use CUSTOM_ELEMENTS_SCHEMA
systemjs.config.js
map: {
...
'ng2-table': 'npm:ng2-table'
},
packages: {
...
'ng2-table': {
defaultExtension: 'js'
}
}
After long time I close this issue.
In my case I have these structure:
src
--app
-- app.module
-- TravelPlan
-- travel-plan.module
-- test.component
So, I was trying put the ng2-smart-table in app.module, but I was wrong. The correct is put in travel-plan.module.