Skip to content

Commit 96f4310

Browse files
authored
docs(state-tutorial): add golbal state (rx-angular#337)
1 parent fc97448 commit 96f4310

25 files changed

+591
-265
lines changed

apps/state-demo/src/app/app-component/app.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
<mat-toolbar>Menu</mat-toolbar>
1111
<mat-nav-list>
1212
<h3 matSubheader>Basics Tutorial</h3>
13-
<a mat-list-item [routerLink]="['demo-basics']"></a>
1413
<a mat-list-item [routerLink]="['demo-basics/setup']">Setup</a>
1514
<a mat-list-item [routerLink]="['demo-basics/input-bindings']">Input Bindings</a>
1615
<a mat-list-item [routerLink]="['demo-basics/output-bindings']">Output Bindings</a>
16+
<a mat-list-item [routerLink]="['demo-basics/global-state']">Global State</a>
1717
<a mat-list-item [routerLink]="['demo-basics/side-effects']">Side Effects</a>
1818
<a mat-list-item [routerLink]="['demo-basics/presenter-pattern']">Presenter Pattern</a>
1919
<a mat-list-item [routerLink]="['demo-basics/solution']">Solution</a>

apps/state-demo/src/app/examples/demo-basics/1-setup/Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ interface ComponentState {
3838
listExpanded: boolean;
3939
}
4040

41-
export class SetupReactiveComponentStateContainerComponent extends RxState<ComponentState> {
41+
export class SetupReactiveComponentStateContainerComponent extends RxState<ComponentState> ... {
4242
```
4343
4444
Also, a `super` in the constructor is needed as we extend from another class.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import {
2+
ChangeDetectionStrategy,
3+
Component,
4+
Input,
5+
OnDestroy,
6+
OnInit,
7+
Output,
8+
} from '@angular/core';
9+
import { RxState } from '@rx-angular/state';
10+
import { distinctUntilKeyChanged, map, startWith, switchMap, tap } from 'rxjs/operators';
11+
import {
12+
ListServerItem,
13+
ListService,
14+
} from '../../../data-access/list-resource';
15+
import { interval, Subject, Subscription } from 'rxjs';
16+
17+
export interface DemoBasicsItem {
18+
id: string;
19+
name: string;
20+
}
21+
22+
interface ComponentState {
23+
refreshInterval: number;
24+
list: DemoBasicsItem[];
25+
listExpanded: boolean;
26+
}
27+
28+
const initComponentState = {
29+
refreshInterval: 10000,
30+
listExpanded: false,
31+
list: [],
32+
};
33+
34+
@Component({
35+
selector: 'setup-solution',
36+
template: `
37+
<h3>
38+
Setup
39+
</h3>
40+
{{model$ | async | json}}
41+
<mat-expansion-panel
42+
(expandedChange)="listExpanded = $event; listExpandedChanges.next($event)"
43+
[expanded]="listExpanded">
44+
<mat-expansion-panel-header class="list">
45+
<mat-progress-bar *ngIf="false" [mode]="'query'"></mat-progress-bar>
46+
<mat-panel-title>
47+
List
48+
</mat-panel-title>
49+
<mat-panel-description>
50+
<span
51+
>{{ (storeList$ | async)?.length }} Repositories Updated every:
52+
{{ _refreshInterval }} ms
53+
</span>
54+
</mat-panel-description>
55+
</mat-expansion-panel-header>
56+
57+
<button
58+
mat-raised-button
59+
color="primary"
60+
(click)="onRefreshClicks($event)"
61+
>
62+
Refresh List
63+
</button>
64+
65+
<ng-container *ngIf="storeList$ | async as list">
66+
<div *ngIf="list?.length; else noList">
67+
<mat-list>
68+
<mat-list-item *ngFor="let item of list">
69+
{{ item.name }}
70+
</mat-list-item>
71+
</mat-list>
72+
</div>
73+
</ng-container>
74+
75+
<ng-template #noList>
76+
<mat-card>No list given!</mat-card>
77+
</ng-template>
78+
</mat-expansion-panel>
79+
`,
80+
styles: [
81+
`
82+
.list .mat-expansion-panel-header {
83+
position: relative;
84+
}
85+
86+
.list .mat-expansion-panel-header mat-progress-bar {
87+
position: absolute;
88+
top: 0px;
89+
left: 0;
90+
}
91+
92+
.list .mat-expansion-panel-content .mat-expansion-panel-body {
93+
padding-top: 10px;
94+
}
95+
`,
96+
],
97+
changeDetection: ChangeDetectionStrategy.OnPush,
98+
})
99+
export class SetupSolution extends RxState<ComponentState> implements OnInit, OnDestroy {
100+
model$ = this.select();
101+
102+
intervalSubscription = new Subscription();
103+
listExpandedChanges = new Subject<boolean>();
104+
storeList$ = this.listService.list$.pipe(
105+
map(this.parseListItems),
106+
startWith(initComponentState.list)
107+
);
108+
109+
_refreshInterval: number = initComponentState.refreshInterval;
110+
@Input()
111+
set refreshInterval(refreshInterval: number) {
112+
if (refreshInterval > 4000) {
113+
this._refreshInterval = refreshInterval;
114+
this.resetRefreshTick();
115+
}
116+
}
117+
118+
listExpanded: boolean = initComponentState.listExpanded;
119+
@Output()
120+
listExpandedChange = this.listExpandedChanges;
121+
122+
constructor(private listService: ListService) {
123+
super();
124+
this.set(initComponentState);
125+
}
126+
127+
ngOnDestroy(): void {
128+
this.intervalSubscription.unsubscribe();
129+
}
130+
131+
ngOnInit(): void {
132+
this.resetRefreshTick();
133+
}
134+
135+
resetRefreshTick() {
136+
this.intervalSubscription.unsubscribe();
137+
this.intervalSubscription = interval(this._refreshInterval)
138+
.pipe(tap((_) => this.listService.refetchList()))
139+
.subscribe();
140+
}
141+
142+
onRefreshClicks(event) {
143+
this.listService.refetchList();
144+
}
145+
146+
parseListItems(l: ListServerItem[]): DemoBasicsItem[] {
147+
return l.map(({ id, name }) => ({ id, name }));
148+
}
149+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ const initComponentState = {
3939
</h3>
4040
<mat-expansion-panel
4141
(expandedChange)="listExpanded = $event; listExpandedChanges.next($event)"
42-
[expanded]="listExpanded"
43-
>
42+
[expanded]="listExpanded">
4443
<mat-expansion-panel-header class="list">
4544
<mat-progress-bar *ngIf="false" [mode]="'query'"></mat-progress-bar>
4645
<mat-panel-title>

apps/state-demo/src/app/examples/demo-basics/2-input-bindings/Readme.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,13 @@ set refreshInterval(refreshInterval: number) {
2626

2727
We also have to adopt the related method `resetRefreshTick` where `_refreshInterval`is used.
2828
As `refreshInterval` already is part of the components' state,
29-
we can easily select the value with `this.select('refreshInterval')` and use the `interval` operator to create the new interval.
29+
we can easily select the value with `this.get('refreshInterval')` and use the `interval` operator to create the new interval.
3030

3131
```typescript
32-
import {..., switchMap} from 'rxjs/operators';
33-
...
34-
3532
resetRefreshTick() {
3633
this.intervalSubscription.unsubscribe();
37-
this.intervalSubscription = this.select('refreshInterval')
38-
.pipe(
39-
switchMap(ms => interval(ms)),
40-
tap(_ => this.store.dispatch(fetchRepositoryList({}))))
34+
this.intervalSubscription = interval(this.get('refreshInterval'))
35+
.pipe(tap((_) => this.listService.refetchList()))
4136
.subscribe();
4237
}
4338
```

apps/state-demo/src/app/examples/demo-basics/2-input-bindings/input-bindings.solution.component.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
Output,
88
} from '@angular/core';
99
import { RxState } from '@rx-angular/state';
10-
import { distinctUntilKeyChanged, map, switchMap, tap } from 'rxjs/operators';
10+
import { distinctUntilKeyChanged, map, startWith, switchMap, tap } from 'rxjs/operators';
1111
import {
1212
ListServerItem,
1313
ListService,
@@ -39,16 +39,17 @@ const initComponentState = {
3939
</h3>
4040
<mat-expansion-panel
4141
*ngIf="model$ | async as vm"
42-
(expandedChange)="listExpandedChanges.next($event)"
43-
[expanded]="vm.listExpanded"
42+
(expandedChange)="listExpanded = $event; listExpandedChanges.next($event)"
43+
[expanded]="listExpanded"
4444
>
45-
<mat-expansion-panel-header>
45+
<mat-expansion-panel-header class="list">
46+
<mat-progress-bar *ngIf="false" [mode]="'query'"></mat-progress-bar>
4647
<mat-panel-title>
4748
List
4849
</mat-panel-title>
4950
<mat-panel-description>
50-
<span>
51-
{{ vm.list.length }} Repositories Updated every:
51+
<span
52+
>{{ (storeList$ | async)?.length }} Repositories Updated every:
5253
{{ vm.refreshInterval }} ms
5354
</span>
5455
</mat-panel-description>
@@ -62,13 +63,15 @@ const initComponentState = {
6263
Refresh List
6364
</button>
6465
65-
<div *ngIf="vm.list.length; else noList">
66-
<mat-list>
67-
<mat-list-item *ngFor="let item of vm.list">
68-
{{ item.name }}
69-
</mat-list-item>
70-
</mat-list>
71-
</div>
66+
<ng-container *ngIf="storeList$ | async as list">
67+
<div *ngIf="list?.length; else noList">
68+
<mat-list>
69+
<mat-list-item *ngFor="let item of list">
70+
{{ item.name }}
71+
</mat-list-item>
72+
</mat-list>
73+
</div>
74+
</ng-container>
7275
7376
<ng-template #noList>
7477
<mat-card>No list given!</mat-card>
@@ -79,29 +82,30 @@ const initComponentState = {
7982
})
8083
export class InputBindingsSolution extends RxState<ComponentState>
8184
implements OnInit, OnDestroy {
85+
model$ = this.select();
86+
8287
intervalSubscription = new Subscription();
8388
listExpandedChanges = new Subject<boolean>();
84-
85-
model$ = this.select();
89+
storeList$ = this.listService.list$.pipe(
90+
map(this.parseListItems),
91+
startWith(initComponentState.list)
92+
);
8693

8794
@Input()
8895
set refreshInterval(refreshInterval: number) {
89-
if (refreshInterval > 100) {
90-
this.set({ refreshInterval: refreshInterval });
96+
if (refreshInterval > 4000) {
97+
this.set({refreshInterval});
9198
this.resetRefreshTick();
9299
}
93100
}
94101

102+
listExpanded: boolean = initComponentState.listExpanded;
95103
@Output()
96-
listExpandedChange = this.$.pipe(distinctUntilKeyChanged('listExpanded'));
104+
listExpandedChange = this.listExpandedChanges;
97105

98106
constructor(private listService: ListService) {
99107
super();
100108
this.set(initComponentState);
101-
this.connect(
102-
this.listExpandedChanges.pipe(map((listExpanded) => ({ listExpanded })))
103-
);
104-
this.connect('list', this.listService.list$.pipe(map(this.parseListItems)));
105109
}
106110

107111
ngOnDestroy(): void {
@@ -114,11 +118,8 @@ export class InputBindingsSolution extends RxState<ComponentState>
114118

115119
resetRefreshTick() {
116120
this.intervalSubscription.unsubscribe();
117-
this.intervalSubscription = this.select('refreshInterval')
118-
.pipe(
119-
switchMap((ms) => interval(ms)),
120-
tap((_) => this.listService.refetchList())
121-
)
121+
this.intervalSubscription = interval(this.get('refreshInterval'))
122+
.pipe(tap((_) => this.listService.refetchList()))
122123
.subscribe();
123124
}
124125

apps/state-demo/src/app/examples/demo-basics/2-input-bindings/input-bindings.start.component.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '../../../data-access/list-resource';
1313
import { interval, Subject, Subscription } from 'rxjs';
1414
import { map, startWith, tap } from 'rxjs/operators';
15+
import { RxState } from '@rx-angular/state';
1516

1617
export interface DemoBasicsItem {
1718
id: string;
@@ -37,6 +38,7 @@ const initComponentState = {
3738
<h3>
3839
Input Bindings
3940
</h3>
41+
{{model$ | async | json}}
4042
<mat-expansion-panel
4143
(expandedChange)="listExpanded = $event; listExpandedChanges.next($event)"
4244
[expanded]="listExpanded"
@@ -96,7 +98,9 @@ const initComponentState = {
9698
],
9799
changeDetection: ChangeDetectionStrategy.OnPush,
98100
})
99-
export class InputBindingsStart implements OnInit, OnDestroy {
101+
export class InputBindingsStart extends RxState<ComponentState> implements OnInit, OnDestroy {
102+
model$ = this.select();
103+
100104
intervalSubscription = new Subscription();
101105
listExpandedChanges = new Subject<boolean>();
102106
storeList$ = this.listService.list$.pipe(
@@ -117,7 +121,10 @@ export class InputBindingsStart implements OnInit, OnDestroy {
117121
@Output()
118122
listExpandedChange = this.listExpandedChanges;
119123

120-
constructor(private listService: ListService) {}
124+
constructor(private listService: ListService) {
125+
super();
126+
this.set(initComponentState);
127+
}
121128

122129
ngOnDestroy(): void {
123130
this.intervalSubscription.unsubscribe();

0 commit comments

Comments
 (0)