@@ -10,8 +10,8 @@ import {
1010 ChangeDetectorRef ,
1111 OnChanges
1212} from '@angular/core' ;
13- import { hasValue , isNotEmpty } from '../empty.util' ;
14- import { from as fromPromise , Observable , of as observableOf , Subscription } from 'rxjs' ;
13+ import { hasNoValue , hasValue , isNotEmpty } from '../empty.util' ;
14+ import { combineLatest , from as fromPromise , Observable , of as observableOf , Subscription } from 'rxjs' ;
1515import { ThemeService } from './theme.service' ;
1616import { catchError , switchMap , map } from 'rxjs/operators' ;
1717import { GenericConstructor } from '../../core/shared/generic-constructor' ;
@@ -25,6 +25,7 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges
2525 @ViewChild ( 'vcr' , { read : ViewContainerRef } ) vcr : ViewContainerRef ;
2626 protected compRef : ComponentRef < T > ;
2727
28+ protected lazyLoadObs : Observable < any > ;
2829 protected lazyLoadSub : Subscription ;
2930 protected themeSub : Subscription ;
3031
@@ -43,50 +44,73 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges
4344 protected abstract importUnthemedComponent ( ) : Promise < any > ;
4445
4546 ngOnChanges ( changes : SimpleChanges ) : void {
46- // if an input or output has changed
47- if ( this . inAndOutputNames . some ( ( name : any ) => hasValue ( changes [ name ] ) ) ) {
48- this . connectInputsAndOutputs ( ) ;
47+ if ( hasNoValue ( this . compRef ) ) {
48+ // sometimes the component has not been initialized yet, so it first needs to be initialized
49+ // before being called again
50+ this . initComponentInstance ( changes ) ;
51+ } else {
52+ // if an input or output has changed
53+ if ( this . inAndOutputNames . some ( ( name : any ) => hasValue ( changes [ name ] ) ) ) {
54+ this . connectInputsAndOutputs ( ) ;
55+ if ( this . compRef ?. instance && 'ngOnChanges' in this . compRef . instance ) {
56+ ( this . compRef . instance as any ) . ngOnChanges ( changes ) ;
57+ }
58+ }
4959 }
5060 }
5161
5262 ngOnInit ( ) : void {
5363 this . destroyComponentInstance ( ) ;
54- this . themeSub = this . themeService . getThemeName$ ( ) . subscribe ( ( ) => {
55- this . renderComponentInstance ( ) ;
56- } ) ;
64+ this . initComponentInstance ( ) ;
5765 }
5866
5967 ngOnDestroy ( ) : void {
6068 [ this . themeSub , this . lazyLoadSub ] . filter ( ( sub ) => hasValue ( sub ) ) . forEach ( ( sub ) => sub . unsubscribe ( ) ) ;
6169 this . destroyComponentInstance ( ) ;
6270 }
6371
64- protected renderComponentInstance ( ) : void {
65- this . destroyComponentInstance ( ) ;
72+ initComponentInstance ( changes ?: SimpleChanges ) {
73+ this . themeSub = this . themeService ?. getThemeName$ ( ) . subscribe ( ( ) => {
74+ this . renderComponentInstance ( changes ) ;
75+ } ) ;
76+ }
6677
78+ protected renderComponentInstance ( changes ?: SimpleChanges ) : void {
6779 if ( hasValue ( this . lazyLoadSub ) ) {
6880 this . lazyLoadSub . unsubscribe ( ) ;
6981 }
7082
71- this . lazyLoadSub = this . resolveThemedComponent ( this . themeService . getThemeName ( ) ) . pipe (
72- switchMap ( ( themedFile : any ) => {
73- if ( hasValue ( themedFile ) && hasValue ( themedFile [ this . getComponentName ( ) ] ) ) {
74- // if the file is not null, and exports a component with the specified name,
75- // return that component
76- return [ themedFile [ this . getComponentName ( ) ] ] ;
77- } else {
78- // otherwise import and return the default component
79- return fromPromise ( this . importUnthemedComponent ( ) ) . pipe (
80- map ( ( unthemedFile : any ) => {
81- return unthemedFile [ this . getComponentName ( ) ] ;
82- } )
83- ) ;
84- }
85- } ) ,
86- ) . subscribe ( ( constructor : GenericConstructor < T > ) => {
83+ if ( hasNoValue ( this . lazyLoadObs ) ) {
84+ this . destroyComponentInstance ( ) ;
85+
86+ this . lazyLoadObs = combineLatest ( [
87+ observableOf ( changes ) ,
88+ this . resolveThemedComponent ( this . themeService . getThemeName ( ) ) . pipe (
89+ switchMap ( ( themedFile : any ) => {
90+ if ( hasValue ( themedFile ) && hasValue ( themedFile [ this . getComponentName ( ) ] ) ) {
91+ // if the file is not null, and exports a component with the specified name,
92+ // return that component
93+ return [ themedFile [ this . getComponentName ( ) ] ] ;
94+ } else {
95+ // otherwise import and return the default component
96+ return fromPromise ( this . importUnthemedComponent ( ) ) . pipe (
97+ map ( ( unthemedFile : any ) => {
98+ return unthemedFile [ this . getComponentName ( ) ] ;
99+ } )
100+ ) ;
101+ }
102+ } ) ) ,
103+ ] ) ;
104+ }
105+
106+ this . lazyLoadSub = this . lazyLoadObs . subscribe ( ( [ simpleChanges , constructor ] : [ SimpleChanges , GenericConstructor < T > ] ) => {
87107 const factory = this . resolver . resolveComponentFactory ( constructor ) ;
88108 this . compRef = this . vcr . createComponent ( factory ) ;
89- this . connectInputsAndOutputs ( ) ;
109+ if ( hasValue ( simpleChanges ) ) {
110+ this . ngOnChanges ( simpleChanges ) ;
111+ } else {
112+ this . connectInputsAndOutputs ( ) ;
113+ }
90114 this . cdr . markForCheck ( ) ;
91115 } ) ;
92116 }
0 commit comments