I'm trying to use Typeform library in my application, but I have a lot problems with it. After loading the js scripts, the Angular zone is wrong and I get this message:
Error: Zone.js has detected that ZoneAwarePromise
(window|global).Promise
has been overwritten. Most likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)
The code of my app.component.ts is:
import { Component, Inject, AfterViewInit} from '@angular/core';
import { DOCUMENT } from '@angular/common';
import * as typeformEmbed from '@typeform/embed';
@Component({
selector: 'my-app',
template: `<div #my_typeform></div>`,
})
export class AppComponent implements AfterViewInit {
constructor(
@Inject(DOCUMENT) private document: Document
){}
ngAfterViewInit() {
const element = this.document.getElementById.call(document, 'my_typeform');
typeformEmbed.makeWidget(element, 'https://jonathan.typeform.com/to/zvlr4L', { onSubmit: () => console.log('Close') });
}
}
I have tried to run manually ngZone to ensure that it's ran inside Angular zone, but didn't work. In this case, app.component.ts was like
import { Component, Inject, AfterViewInit, NgZone} from '@angular/core';
import { DOCUMENT } from '@angular/common';
import * as typeformEmbed from '@typeform/embed';
@Component({
selector: 'my-app',
template: `<div #my_typeform></div>`,
})
export class AppComponent implements AfterViewInit {
constructor(
@Inject(DOCUMENT) private document: any,
@Inject(NgZone) private ngZone: NgZone
){}
ngAfterViewInit() {
this.ngZone.run(() => {
const element = this.document.getElementById.call(document, 'my_typeform');
typeformEmbed.makeWidget(element, 'https://jonathan.typeform.com/to/zvlr4L', { onSubmit: () => console.log('Close') });
});
}
}
I have also tried to import 'zone.js/dist/zone-patch-rxjs' in my polyfill.ts file, but it didn't work either.
You can see a project with the minimal code to reproduce it in https://stackblitz.com/edit/angular-issue-repro2-daytbo
Any clue or help is really welcome!
Thanks in advance!
js provides a mechanism, called zones, for encapsulating and intercepting asynchronous activities in the browser (e.g. setTimeout , , promises). These zones are execution contexts that allow Angular to track the start and completion of asynchronous activities and perform tasks as required (e.g. change detection). Zone.
js is a way of creating a new Context and getting the code executed within that context/Zone. Any code enclosed within a Zone whether synchronous or asynchronous is executed within the same context. Zone. js is basically used to create new context and execute code within it.
A ZoneAwarePromise is still functionally identical to a normal Promise, but internally stays aware of a Zone 's execution context, and the Zone can know when that Promise completes. In Angular, this execution context almost always means running change detection.
For those still looking for a VERY easy fix for this, this is what worked for me.
Step 1) Move your import 'zone/dist/...'
stuff from your polyfill.ts
file to your main.ts
file before your bootstrap.
So in your main.ts
file, you should have something like:
import 'zone.js/dist/zone' // Included with Angular CLI.
platformBrowserDynamic()
.bootstrapModule(AppModule, { ngZone: new NgZone({}) })
And just be sure you've totally removed it from your polyfill.ts
file
Step 2) Profit.
OK, so let me explain what's actually happening (that I noticed):
There's a race condition where occasionally the polyfilled promise gets added AFTER the zone.js
module overrides the native promise. This is what causes Zone to recognize that it's been replaced and throw that error.
This happened regardless of the order in the polyfill.ts
I put the imports in.
I originally tried putting the loader for zone.js
in a timeout with a short timer (100ms). This worked to prevent the error message we're all seeing, but occasionally didn't fire fast enough to load the zone.js
module before hitting the bootstrap.
So obviously this was causing a race condition. (Of my own making.)
The thought then was to make the zone.js
import OFFICIALLY last before loading the bootstrap. I wanted to make sure that was going to work:
I was able to test this by putting a console.log
in the main.ts
and the polyfill.ts
files. What I saw was that the polyfill.ts
is always loaded before the main.ts
.
So placing the import 'zone.js/dist/zone'
line in the main.ts
solves this problem once and for all. Then your polyfill.ts
file is free to pull in and load any modules necessary before getting that zone.js
file imported.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With