5

I'm working on an electron application, whose client side is written in Angular2.

I'm having the classic problem that a lot of people have encountered (eg. here and here), namely that I'm updating my component's data, but the view doesn't get updated because Angular doesn't know that the data has changed. The solutions people suggest (see above and also here) is to manually run change detection, either on the whole component tree, or part of it (similar to Angular 1's $rootScope.$digest and $scope.$digest).

However, I'd like to avoid wrapping all my data changes in zone.run() calls, as it slightly defeats the purpose of using Angular.

I'm pretty sure I know why this happens: I'm creating Bluebird Promises outside of Angular, in electron code (ie, the main process), and these aren't Zone aware, so they don't notify Angular of the changes.

I don't know how to solve it, though. What can I do to create Zone aware promises in my electron code, to avoid having to manually run change detection all the time? Can I convert my Bluebird Promises to Zone aware Promises somehow?

EDIT: I think I was wrong, Bluebird promises aren't Zone aware even if created within angular. They're just not Zone aware in general.

EDIT 2: I was completely wrong in the previous edit. Bluebird promises work just fine with zones. However, in the context of an electron application, creating a promise in the main electron process and using it in the renderer process (where Angular lives), doesn't work, as the returned promise isn't zone-aware. Creating the promise from Angular code worked.

Community
  • 1
  • 1
FrontierPsycho
  • 743
  • 7
  • 25
  • Isn't the main process the process that runs outside of the browser? I don't think any promises there would trigger changes in the browser. – Jacob Aug 09 '16 at 15:54
  • I was expecting them to, because even though I'm creating the Promises in the main process, I'm requesting them and adding `.then()` handlers on the Angular side. – FrontierPsycho Aug 09 '16 at 16:07

2 Answers2

4

Promises don't make Angular run change detection with ChangeDetectionStrategy.OnPush except when you use the async pipe ... | async.

When code is initialized outside Angular2 it runs outside Angulars zone. What you can do is to move initialization inside your Angular2 code or use ´zone.run(...)to move execution inside Angulars zone. There is nothing bad aboutzone.run(...)`.

If the code executed only changes local properties of a component you can use ChangeDetectorRef.detectChanges() to run change detection for this component.

If the code causes changes in other components (like for example this.router.navigate(...), then detectChanges() is not sufficient. For this case zone.run() should be used.

setTimeout(...) triggers change detection for the whole application and should be avoided as a way to invoke change detection manually.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Thank you for the answer. `zone.run()` (and `detectChanges()`) isn't *that* bad, but we have to remember to call it in the right places. In any case, that's what we're going with right now. My question is more about whether there's a way to make bluebird promises automatically behave like angular promises (which work), as bluebird promises have a bunch of useful features that native ones don't. – FrontierPsycho Aug 10 '16 at 08:36
  • I don't know bluebird promises. Normal promises don't do anything special in Angular2 AFAIK, it's just that `.then(...)` is usually called because of an async call being completed in the browser, which is what Angulars zone gets notified about and then runs change detection. I would expect `bluebird` promises to work the same. Maybe a bug report in the bluebird source repository might be a good idea if it doesn't work. – Günter Zöchbauer Aug 10 '16 at 08:41
  • 1
    I inspected a regular promise that I had created, in the dev console in Chrome, and it seemed to actually be a `ZoneAwarePromise`, which is a special wrapper around promises, provided by zone.js. That's why I think they're special. – FrontierPsycho Aug 10 '16 at 08:58
  • Ok, didn't know that. I'd assume the same then. – Günter Zöchbauer Aug 10 '16 at 08:59
0

As explained in EDIT #2, the problem was that creating a promise in the main electron process made the promise non-zone-aware. Creating the promise from Angular solved it.

FrontierPsycho
  • 743
  • 7
  • 25