From 0c58bd4f1d795232a92ce714f73e2a3eb486c482 Mon Sep 17 00:00:00 2001 From: Mark Berry Date: Fri, 4 Sep 2020 04:20:14 -0500 Subject: [PATCH 1/4] Run setProps in the NgZone --- .../src/client/preview/angular/components/app.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/angular/src/client/preview/angular/components/app.component.ts b/app/angular/src/client/preview/angular/components/app.component.ts index f0a094788c9d..bf18a5b88df7 100644 --- a/app/angular/src/client/preview/angular/components/app.component.ts +++ b/app/angular/src/client/preview/angular/components/app.component.ts @@ -15,6 +15,7 @@ import { SimpleChanges, SimpleChange, ChangeDetectorRef, + NgZone, } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; import { first } from 'rxjs/operators'; @@ -36,6 +37,7 @@ export class AppComponent implements OnInit, OnDestroy { constructor( private cfr: ComponentFactoryResolver, private changeDetectorRef: ChangeDetectorRef, + private ngZone: NgZone, @Inject(STORY) private data: Observable ) {} @@ -51,7 +53,7 @@ export class AppComponent implements OnInit, OnDestroy { ); this.subscription = this.data.subscribe((newData) => { - this.setProps(instance, newData); + this.ngZone.run(() => this.setProps(instance, newData)) childChangeDetectorRef.markForCheck(); // Must detect changes on the current component in order to update any changes in child component's @HostBinding properties (angular/angular#22560) this.changeDetectorRef.detectChanges(); From c1f7f0a943526d2abfbdeb8a8394506d6768015b Mon Sep 17 00:00:00 2001 From: Mark Berry Date: Fri, 4 Sep 2020 04:34:29 -0500 Subject: [PATCH 2/4] Add semicolon --- .../src/client/preview/angular/components/app.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/angular/src/client/preview/angular/components/app.component.ts b/app/angular/src/client/preview/angular/components/app.component.ts index bf18a5b88df7..901cc8bf1c98 100644 --- a/app/angular/src/client/preview/angular/components/app.component.ts +++ b/app/angular/src/client/preview/angular/components/app.component.ts @@ -53,7 +53,7 @@ export class AppComponent implements OnInit, OnDestroy { ); this.subscription = this.data.subscribe((newData) => { - this.ngZone.run(() => this.setProps(instance, newData)) + this.ngZone.run(() => this.setProps(instance, newData)); childChangeDetectorRef.markForCheck(); // Must detect changes on the current component in order to update any changes in child component's @HostBinding properties (angular/angular#22560) this.changeDetectorRef.detectChanges(); From 915f16fd030de0ea324c3abdc98ccc25b67d09fc Mon Sep 17 00:00:00 2001 From: Mark Berry Date: Wed, 18 Nov 2020 00:56:42 -0600 Subject: [PATCH 3/4] Re-emit story data in ngZone --- .../angular/components/app.component.ts | 4 +-- .../src/client/preview/angular/helpers.ts | 27 +++++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app/angular/src/client/preview/angular/components/app.component.ts b/app/angular/src/client/preview/angular/components/app.component.ts index d70527b07673..57bd79442abc 100644 --- a/app/angular/src/client/preview/angular/components/app.component.ts +++ b/app/angular/src/client/preview/angular/components/app.component.ts @@ -15,7 +15,6 @@ import { SimpleChanges, SimpleChange, ChangeDetectorRef, - NgZone, } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; import { first } from 'rxjs/operators'; @@ -39,7 +38,6 @@ export class AppComponent implements OnInit, OnDestroy { constructor( private cfr: ComponentFactoryResolver, private changeDetectorRef: ChangeDetectorRef, - private ngZone: NgZone, @Inject(STORY) private data: Observable ) {} @@ -55,7 +53,7 @@ export class AppComponent implements OnInit, OnDestroy { ); this.subscription = this.data.subscribe((newData) => { - this.ngZone.run(() => this.setProps(instance, newData)); + this.setProps(instance, newData); childChangeDetectorRef.markForCheck(); // Must detect changes on the current component in order to update any changes in child component's @HostBinding properties (angular/angular#22560) this.changeDetectorRef.detectChanges(); diff --git a/app/angular/src/client/preview/angular/helpers.ts b/app/angular/src/client/preview/angular/helpers.ts index fa39fdcc5428..97d41f65bfc6 100644 --- a/app/angular/src/client/preview/angular/helpers.ts +++ b/app/angular/src/client/preview/angular/helpers.ts @@ -1,10 +1,10 @@ // @ts-ignore import { document } from 'global'; -import { enableProdMode, NgModule, Component, NgModuleRef, Type } from '@angular/core'; +import { enableProdMode, NgModule, Component, NgModuleRef, Type, NgZone } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; -import { ReplaySubject } from 'rxjs'; +import { Observable, ReplaySubject, Subscriber } from 'rxjs'; import { StoryFn } from '@storybook/addons'; import { AppComponent } from './components/app.component'; import { STORY } from './app.token'; @@ -18,13 +18,27 @@ declare global { let platform: any = null; let promises: Promise>[] = []; -let storyData = new ReplaySubject(1); +let storyData = new ReplaySubject(1); const moduleClass = class DynamicModule {}; const componentClass = class DynamicComponent {}; type DynamicComponentType = typeof componentClass; +function storyDataFactory(storyData: Observable) { + return (ngZone: NgZone) => new Observable((subscriber: Subscriber) => { + const sub = storyData.subscribe( + (v: T) => { ngZone.run(() => subscriber.next(v)); }, + (err) => { ngZone.run(() => subscriber.error(err)); }, + () => { ngZone.run(() => subscriber.complete()); } + ); + + return () => { + sub.unsubscribe(); + }; + }); +}; + const getModule = ( declarations: (Type | any[])[], entryComponents: (Type | any[])[], @@ -34,13 +48,16 @@ const getModule = ( ) => { // Complete last ReplaySubject and create a new one for the current module storyData.complete(); - storyData = new ReplaySubject(1); + storyData = new ReplaySubject(1); storyData.next(data); const moduleMeta = { declarations: [...declarations, ...(moduleMetadata.declarations || [])], imports: [BrowserModule, FormsModule, ...(moduleMetadata.imports || [])], - providers: [{ provide: STORY, useValue: storyData }, ...(moduleMetadata.providers || [])], + providers: [ + { provide: STORY, useFactory: storyDataFactory(storyData.asObservable()), deps: [ NgZone ] }, + ...(moduleMetadata.providers || []) + ], entryComponents: [...entryComponents, ...(moduleMetadata.entryComponents || [])], schemas: [...(moduleMetadata.schemas || [])], bootstrap: [...bootstrap], From b9ba7a8132c989fc3e23c467172555bca465e459 Mon Sep 17 00:00:00 2001 From: Mark Berry Date: Fri, 20 Nov 2020 23:56:54 -0600 Subject: [PATCH 4/4] Fix lint error --- app/angular/src/client/preview/angular/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/angular/src/client/preview/angular/helpers.ts b/app/angular/src/client/preview/angular/helpers.ts index 97d41f65bfc6..e554b84435b8 100644 --- a/app/angular/src/client/preview/angular/helpers.ts +++ b/app/angular/src/client/preview/angular/helpers.ts @@ -25,9 +25,9 @@ const componentClass = class DynamicComponent {}; type DynamicComponentType = typeof componentClass; -function storyDataFactory(storyData: Observable) { +function storyDataFactory(data: Observable) { return (ngZone: NgZone) => new Observable((subscriber: Subscriber) => { - const sub = storyData.subscribe( + const sub = data.subscribe( (v: T) => { ngZone.run(() => subscriber.next(v)); }, (err) => { ngZone.run(() => subscriber.error(err)); }, () => { ngZone.run(() => subscriber.complete()); }