Skip to content

Commit

Permalink
fix: re-subscribe panel data when panel model changes (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
tFaster committed Sep 8, 2022
1 parent f99a1da commit bef2688
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 62 deletions.
93 changes: 46 additions & 47 deletions projects/demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ChangeDetectionStrategy, Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Observable, of, timer } from 'rxjs';
import { delay, map, Observable, of, tap, timer } from 'rxjs';
import { AddSubPanelsFunction, Panel, StackedPanelTemplateOutletContext } from '@tfaster/stacked-panels';
import { HttpClient } from '@angular/common/http';
import { delay, map, tap } from 'rxjs/operators';
import * as Faker from 'faker';
import { AnimationParams } from '../../../stacked-panels/src/lib/stacked-panel/stacked-panel.animations';

Expand All @@ -14,7 +13,7 @@ import { AnimationParams } from '../../../stacked-panels/src/lib/stacked-panel/s
})
export class AppComponent implements OnInit {

@ViewChild('bodyTemplate', { static: true })
@ViewChild('bodyTemplate', {static: true})
private _demoBodyTemplate: TemplateRef<StackedPanelTemplateOutletContext<DemoPanelData>>;

public rootPanel: Panel<DemoPanelData>;
Expand All @@ -26,7 +25,7 @@ export class AppComponent implements OnInit {
panelGrowHeightTime: '1s',
panelShrinkHeightTime: '1s',
contentFadeAndScaleTime: '1s'*/
}
};

constructor(private _http: HttpClient) {
}
Expand All @@ -40,70 +39,70 @@ export class AppComponent implements OnInit {
header: 'Pedigree',
footerText: 'Click CHILDREN to drill down...',
items: [
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel1' }
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel1'}
]
};
const subPanel1Data: DemoPanelData = {
header: 'Children',
footerText: 'Click CHILDREN to drill down even more...',
items: [
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel2a' },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel2b' }
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel2a'},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel2b'}
]
};
const subPanel2aData: DemoPanelData = {
header: 'Children',
items: [
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() }
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()}
]
};
const subPanel2bData: DemoPanelData = {
header: 'Children',
items: [
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel3' },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel3'},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()}
]
};
const subPanel3Data: DemoPanelData = {
header: 'Children',
items: [
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName() },
{ firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel4' }
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName()},
{firstName: Faker.name.firstName(), lastName: Faker.name.lastName(), drilldown: 'subPanel4'}
]
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@ import {
Component,
HostBinding,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
TemplateRef,
ViewContainerRef
} from '@angular/core';
import { ConfigurableFocusTrapFactory, FocusTrap } from '@angular/cdk/a11y';
import { isObservable, Observable, of, ReplaySubject, Subject, Subscription } from 'rxjs';
import { delay, distinctUntilChanged, map, skip, takeUntil } from 'rxjs/operators';
import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';
import {
combineLatestWith,
delay,
distinctUntilChanged,
isObservable,
map,
Observable,
of,
ReplaySubject,
skip,
startWith,
Subject,
Subscription,
takeUntil
} from 'rxjs';
import { Panel, StackedPanelsController } from '../stacked-panels.types';
import { StackedPanelsService } from '../stacked-panels.service';
import {
Expand All @@ -34,7 +49,7 @@ import {
showHideContentTrigger
]
})
export class StackedPanelComponent<T> implements OnInit, AfterViewInit, OnDestroy {
export class StackedPanelComponent<T> implements OnInit, OnChanges, AfterViewInit, OnDestroy {

private _showHideAnimationState: ShowHideAnimationState;

Expand Down Expand Up @@ -64,24 +79,29 @@ export class StackedPanelComponent<T> implements OnInit, AfterViewInit, OnDestro

public isLoading: boolean = false;

private _focusTrap: FocusTrap;
private _focusTrap: ConfigurableFocusTrap;

private readonly _destroy$: Subject<void> = new Subject<void>();

private readonly _panelData$: Subject<T> = new ReplaySubject<T>(1);

private readonly _shownPanels$: Observable<Panel[]> = this._stackedPanelsService.shownPanels$;

private _panelChange$: Subject<void> = new Subject<void>();

public readonly panelData$: Observable<T> = this._panelData$.asObservable();

public readonly contentVisibleOrHidden$: Observable<ContentVisibleState> = this.topPanel$.pipe(
map<Panel, ContentVisibleState>((topPanel: Panel) => topPanel.id === this.panel.id ? 'visible' : 'hidden'),
distinctUntilChanged()
)
);

private readonly _shownOrHidden$: Observable<ShowHideAnimationState> = this._shownPanels$.pipe(
map<Panel[], ShowHideAnimationState>((shownPanels: Panel[]) => shownPanels.map((panel: Panel) => panel.id).includes(this.panel.id) ? 'shown' : 'hidden'),
distinctUntilChanged()
map<Panel[], ShowHideAnimationState>((shownPanels: Panel[]) => shownPanels.map((panel: Panel) => panel.id).includes(this.panel.id)
? 'shown' : 'hidden'),
distinctUntilChanged(),
combineLatestWith(this._panelChange$.pipe(startWith(null))),
map(([showHideState]: [ShowHideAnimationState, void]) => showHideState)
);

private _dataSubscription: Subscription;
Expand All @@ -97,6 +117,12 @@ export class StackedPanelComponent<T> implements OnInit, AfterViewInit, OnDestro
this._initShowHideAnimation();
}

public ngOnChanges(changes: SimpleChanges): void {
if (changes['panel'] && changes['panel'].currentValue) {
this._panelChange$.next();
}
}

public ngAfterViewInit(): void {
this._registerFocusTrap();
}
Expand All @@ -119,6 +145,7 @@ export class StackedPanelComponent<T> implements OnInit, AfterViewInit, OnDestro
).subscribe((showHideState: ShowHideAnimationState) => {
this._showHideAnimationState = showHideState;
if (showHideState === 'shown') {
this._unsubscribePanelData();
this._subscribePanelData();
} else {
this._unsubscribePanelData();
Expand Down
10 changes: 3 additions & 7 deletions projects/stacked-panels/src/lib/stacked-panels.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, isObservable, Observable } from 'rxjs';
import { BehaviorSubject, isObservable, map, Observable } from 'rxjs';
import { GetDataFunction, Panel, StackedPanelsController } from './stacked-panels.types';
import { distinctUntilChanged, map } from 'rxjs/operators';


@Injectable()
Expand All @@ -15,17 +14,14 @@ export class StackedPanelsService {

private readonly _panelDataMap: Map<string, Observable<any>> = new Map<string, Observable<any> | any>();

public readonly panels$: Observable<Panel[]> = this._panels$.pipe(distinctUntilChanged((oldVal, newVal) => oldVal.length === newVal.length));
public readonly panels$: Observable<Panel[]> = this._panels$.asObservable();

public readonly shownPanels$: Observable<Panel[]> = this._shownPanels$.asObservable();

public readonly topPanel$: Observable<Panel> = this._shownPanels$.pipe(
map((shownPanels: Panel[]) => shownPanels[shownPanels.length - 1])
);

constructor() {
}

public initRootPanel<T, C>(rootPanel: Panel<T, C>): void {
this._panels$.next([rootPanel]);
this._showPanel<T, C>(rootPanel);
Expand All @@ -47,7 +43,7 @@ export class StackedPanelsService {
const allPanelsWithoutSubPanelsOfParentPanel: Panel[] = this._panels.filter((panel: Panel) => !subPanelIdsOfParentPanel.includes(panel.id));
subPanelIdsOfParentPanel.forEach((panelId: string) => {
this._panelDataMap.delete(panelId);
})
});
this._panels$.next(allPanelsWithoutSubPanelsOfParentPanel);
}
}
Expand Down
1 change: 1 addition & 0 deletions stacked-panels.iml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
<excludeFolder url="file://$MODULE_DIR$/.angular" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
Expand Down

0 comments on commit bef2688

Please sign in to comment.