-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ngssm-data] Add directive to help with scoped data sources (#228)
- Loading branch information
Showing
10 changed files
with
193 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './is-ngssm-data-source-value-status.pipe'; | ||
export * from './ngssm-data-reload-button/ngssm-data-reload-button.component'; | ||
export * from './ngssm-scoped-data-source.directive'; |
36 changes: 36 additions & 0 deletions
36
projects/ngssm-data/src/lib/ngssm-data/components/ngssm-scoped-data-source.directive.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { of } from 'rxjs'; | ||
|
||
import { StoreMock } from 'ngssm-store/testing'; | ||
|
||
import { NgssmScopedDataSourceDirective } from './ngssm-scoped-data-source.directive'; | ||
import { NgssmDataActionType, NgssmUnregisterDataSourceAction } from '../actions'; | ||
|
||
describe('NgssmScopedDataSourceDirective', () => { | ||
let store: StoreMock; | ||
|
||
beforeEach(() => { | ||
store = new StoreMock({}); | ||
spyOn(store, 'dispatchAction'); | ||
}); | ||
|
||
it('should register the source when created', () => { | ||
const directive = new NgssmScopedDataSourceDirective(store as any); | ||
directive.ngssmScopedDataSource = { | ||
key: 'test', | ||
dataLoadingFunc: () => of([]) | ||
}; | ||
const recentCallArgs = (store.dispatchAction as any).calls.mostRecent().args[0]; | ||
expect(recentCallArgs.type).toEqual(NgssmDataActionType.registerDataSource); | ||
expect(recentCallArgs.dataSource.key).toEqual('test'); | ||
}); | ||
|
||
it('should unregister the source when deleted', () => { | ||
const directive = new NgssmScopedDataSourceDirective(store as any); | ||
directive.ngssmScopedDataSource = { | ||
key: 'test', | ||
dataLoadingFunc: () => of([]) | ||
}; | ||
directive.ngOnDestroy(); | ||
expect(store.dispatchAction).toHaveBeenCalledWith(new NgssmUnregisterDataSourceAction('test')); | ||
}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
projects/ngssm-data/src/lib/ngssm-data/components/ngssm-scoped-data-source.directive.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Directive, Input, OnDestroy } from '@angular/core'; | ||
|
||
import { Store } from 'ngssm-store'; | ||
|
||
import { NgssmDataSource } from '../model'; | ||
import { NgssmRegisterDataSourceAction, NgssmUnregisterDataSourceAction } from '../actions'; | ||
|
||
@Directive({ | ||
selector: '[ngssmScopedDataSource]', | ||
standalone: true | ||
}) | ||
export class NgssmScopedDataSourceDirective implements OnDestroy { | ||
private _dataSource: NgssmDataSource | undefined; | ||
|
||
constructor(private store: Store) {} | ||
|
||
@Input() set ngssmScopedDataSource(value: NgssmDataSource) { | ||
if (this._dataSource) { | ||
throw new Error('Data source is already set.'); | ||
} | ||
this._dataSource = value; | ||
this.store.dispatchAction(new NgssmRegisterDataSourceAction(this._dataSource)); | ||
} | ||
|
||
public ngOnDestroy(): void { | ||
const key = this._dataSource?.key; | ||
if (key) { | ||
this.store.dispatchAction(new NgssmUnregisterDataSourceAction(key)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
...onents/component-with-scoped-data-source/component-with-scoped-data-source.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<p [ngssmScopedDataSource]="dataSource">component-with-scoped-data-source works!</p> |
Empty file.
26 changes: 26 additions & 0 deletions
26
...mponents/component-with-scoped-data-source/component-with-scoped-data-source.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Component, ChangeDetectionStrategy } from '@angular/core'; | ||
import { CommonModule } from '@angular/common'; | ||
import { of } from 'rxjs'; | ||
|
||
import { NgSsmComponent, Store } from 'ngssm-store'; | ||
import { NgssmDataSource, NgssmScopedDataSourceDirective } from 'ngssm-data'; | ||
|
||
@Component({ | ||
selector: 'app-component-with-scoped-data-source', | ||
standalone: true, | ||
imports: [CommonModule, NgssmScopedDataSourceDirective], | ||
templateUrl: './component-with-scoped-data-source.component.html', | ||
styleUrls: ['./component-with-scoped-data-source.component.scss'], | ||
changeDetection: ChangeDetectionStrategy.OnPush | ||
}) | ||
export class ComponentWithScopedDataSourceComponent extends NgSsmComponent { | ||
private static nextId = 1; | ||
public readonly dataSource: NgssmDataSource<string[], unknown> = { | ||
key: `scoped-${ComponentWithScopedDataSourceComponent.nextId++}`, | ||
dataLoadingFunc: () => of([]) | ||
}; | ||
|
||
constructor(store: Store) { | ||
super(store); | ||
} | ||
} |
132 changes: 81 additions & 51 deletions
132
src/app/ngssm-data-demo/components/ngssm-data-demo/ngssm-data-demo.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,81 @@ | ||
<mat-card class="fxFlex flex-column-stretch subcard"> | ||
<mat-card-header> | ||
<mat-card-title class="flex-row-center"> | ||
Data source registered at startup | ||
|
||
@if(store.state() | isNgssmDataSourceValueStatus:teamsKey:'loading') { | ||
<mat-spinner [diameter]="24"></mat-spinner> | ||
} | ||
|
||
</mat-card-title> | ||
</mat-card-header> | ||
<mat-card-content class="flex-column-stretch fxFlex" | ||
[ngssmDisplayOverlay]="store.state() | isNgssmDataSourceValueStatus:teamsKey:'loading'"> | ||
<div class="flex-row-center"> | ||
<ngssm-data-reload-button [dataSourceKeys]="[teamsKey]"></ngssm-data-reload-button> | ||
</div> | ||
<div class="flex-row-center"> | ||
Reload all: <ngssm-data-reload-button [dataSourceKeys]="[teamsKey, playersKey]"></ngssm-data-reload-button> | ||
</div> | ||
|
||
{{teamsSourceValue() | json}} | ||
</mat-card-content> | ||
</mat-card> | ||
|
||
<mat-card class="fxFlex flex-column-stretch subcard"> | ||
<mat-card-header> | ||
<mat-card-title class="flex-row-center"> | ||
Data source not registered at startup | ||
|
||
@if(store.state() | isNgssmDataSourceValueStatus:playersKey:'loading') { | ||
<mat-spinner [diameter]="24"></mat-spinner> | ||
} @else if(store.state() | isNgssmDataSourceValueStatus:playersKey:'error':'none') { | ||
[No data] | ||
} @else if(store.state() | isNgssmDataSourceValueStatus:playersKey:'notRegistered') { | ||
[Not registered] | ||
} | ||
|
||
</mat-card-title> | ||
</mat-card-header> | ||
<mat-card-content class="flex-column-stretch fxFlex"> | ||
<div class="flex-row-center"> | ||
<ngssm-data-reload-button [dataSourceKeys]="[playersKey]"></ngssm-data-reload-button> | ||
<button mat-stroked-button color="primary" (click)="registerPlayers()" class="with-margin-right-12"> | ||
Register players source | ||
</button> | ||
</div> | ||
|
||
|
||
{{playersSourceValue() | json}} | ||
</mat-card-content> | ||
</mat-card> | ||
<div class="fxFlex flex-row-stretch"> | ||
|
||
<div class="fxFlex flex-column-stretch"> | ||
|
||
|
||
<mat-card class="fxFlex flex-column-stretch subcard"> | ||
<mat-card-header> | ||
<mat-card-title class="flex-row-center"> | ||
Data source registered at startup | ||
|
||
@if(store.state() | isNgssmDataSourceValueStatus:teamsKey:'loading') { | ||
<mat-spinner [diameter]="24"></mat-spinner> | ||
} | ||
|
||
</mat-card-title> | ||
</mat-card-header> | ||
<mat-card-content class="flex-column-stretch fxFlex" | ||
[ngssmDisplayOverlay]="store.state() | isNgssmDataSourceValueStatus:teamsKey:'loading'"> | ||
<div class="flex-row-center"> | ||
<ngssm-data-reload-button [dataSourceKeys]="[teamsKey]"></ngssm-data-reload-button> | ||
</div> | ||
<div class="flex-row-center"> | ||
Reload all: <ngssm-data-reload-button | ||
[dataSourceKeys]="[teamsKey, playersKey]"></ngssm-data-reload-button> | ||
</div> | ||
|
||
{{teamsSourceValue() | json}} | ||
</mat-card-content> | ||
</mat-card> | ||
|
||
<mat-card class="fxFlex flex-column-stretch subcard"> | ||
<mat-card-header> | ||
<mat-card-title class="flex-row-center"> | ||
Data source not registered at startup | ||
|
||
@if(store.state() | isNgssmDataSourceValueStatus:playersKey:'loading') { | ||
<mat-spinner [diameter]="24"></mat-spinner> | ||
} @else if(store.state() | isNgssmDataSourceValueStatus:playersKey:'error':'none') { | ||
[No data] | ||
} @else if(store.state() | isNgssmDataSourceValueStatus:playersKey:'notRegistered') { | ||
[Not registered] | ||
} | ||
|
||
</mat-card-title> | ||
</mat-card-header> | ||
<mat-card-content class="flex-column-stretch fxFlex"> | ||
<div class="flex-row-center"> | ||
<ngssm-data-reload-button [dataSourceKeys]="[playersKey]"></ngssm-data-reload-button> | ||
<button mat-stroked-button color="primary" (click)="registerPlayers()" class="with-margin-right-12"> | ||
Register players source | ||
</button> | ||
</div> | ||
|
||
|
||
{{playersSourceValue() | json}} | ||
</mat-card-content> | ||
</mat-card> | ||
|
||
<mat-card class="fxFlex flex-column-stretch subcard"> | ||
<mat-card-header> | ||
<mat-card-title>Component with scoped data source</mat-card-title> | ||
</mat-card-header> | ||
<mat-card-content class="fxFlex flex-column-stretch"> | ||
<button mat-stroked-button color="primary" | ||
(click)="componentWithScopedDatasourceRendered.set(!componentWithScopedDatasourceRendered())"> | ||
@if(componentWithScopedDatasourceRendered()) { | ||
Remove | ||
} @else { | ||
Display | ||
} | ||
component with scoped source | ||
</button> | ||
@if(componentWithScopedDatasourceRendered()) { | ||
<app-component-with-scoped-data-source class="fxFlex"></app-component-with-scoped-data-source> | ||
} | ||
</mat-card-content> | ||
</mat-card> | ||
</div> | ||
<ngssm-ace-editor class="fxFlex" [content]="state()" [editorMode]="'ace/mode/json'" [readonly]="true"> | ||
</ngssm-ace-editor> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters