0

I have encountered a strange problem when using angular 2 beta RC. Events get postponed if I include an external script I wrote into any angular 2 project:

<script>
  (function(r,a,k,e,y,o,u){r['RakrWidgetObject']=y;r[y]=r[y]||function(){
  (r[y].q=r[y].q||[]).push(arguments)},r[y].l=1*new Date();o=a.createElement(k),
  u=a.getElementsByTagName(k)[0];o.async=1;o.src=e;u.parentNode.insertBefore(o,u)
  })(window,document,'script','//cht.technology/rakr.js','rakr');

  rakr('//localhost:3000', 'RAKR-000001');
</script>

Take github project thelgevold/angular-2-samples for example, once I add the below script as I did in https://github.com/tan9/angular-2-samples/tree/event-postponed branch.

The angular 2 application starts to behave strangely, some event changes won't be taking into account by angular until I trigger another event manually, I have to click a button twice to get correct rendering as this recording I uploaded to imgur

enter image description here

I don't know what's happening to the external script I wrote, it's a simple project that only depends on html2canvas and es6-promise, which can capture screenshot using html2canvas and send it to another web service. The bundle was built by webpack, and I tried to build the bundle by using browersify, with no luck.

tan9
  • 3,490
  • 2
  • 18
  • 21

2 Answers2

1

This is a caveat with how Zone.js works. Zone.js patches async browser events and provides an API in which Angular uses to determine when changes happen and when to run change detection in order to update the UI.

In the case of your third-party library that uses the browser Promise API, it needs to be loaded before Zone.js is loaded via script tag. This is so that async events are patched so it will be run in the "zone" that Angular runs in. Events running outside the zone won't be picked up unless change detection is run manually, or the event is run in the context of the Angular zone.

Brandon
  • 706
  • 6
  • 4
  • I removed the Promise polyfill (es6-promise) from the external project, and everything works like a charm. – tan9 May 17 '16 at 14:58
0

As explained by brandon, make the code run inside Angulars zone

inject NgZone

constructor(private ngZone:NgZone){}

...

this.zone.run(() => ... /* code here that modifies Angulars model from the outside */);

You can also get the zone outside Angular

bootstrap(AppComponent, ...).then((ref => ref.instance.injector.get(NgZone));

(Not sure if this is 100% correct, I'm just on my phone and looking up is cumbersome. Please post a comment if you can't make it work.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • The external script is angular agnostic, and should be work on any application with or without angular 2. I think it is counterintuitive to have any Angular 2 or Zone.js related references in the script. – tan9 May 17 '16 at 01:40