Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten

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!

like image 532
user2132866 Avatar asked Sep 18 '19 15:09

user2132866


People also ask

What is Zone js in Angular?

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.

What is Zonejs?

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.

What is zone aware promise?

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.


1 Answers

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.

like image 190
Matthew Kernes Avatar answered Oct 28 '22 13:10

Matthew Kernes