Getting Started
Angular Eagle Eye is an independent state manager as a service running alongside an Angular application, which once created, can be plugged into any part of the application as needed. There is no bound to the number of instances allowed per application.
npm install --save @webkrafters/ng-eagleeyeCreating the Angular Eagle Eye store
Two services are provided for this purpose depending on need.- ContextService: the core applicaton state resides here. Use the
provideContextService(...)to make this service available to the Angular DI system. More on this here. - StreamService: this is a UI-friendly service which observes and streams changes to the application state in real-time. Use the
provideStreamService(...)to make this service available to the Angular DI system. More on this here.
Assuming the following default state data:
1
2
3
4
5
6
7
8
9
export const state = {
a: {
b: {
c: null as unknown as string,
x: { y: { z: [ 2022 ] } }
}
}
};
export type State = typeof state;AS A SCOPED CONTEXT
To make a context injectable within a limited scope (i.e a limited section of the application), provide it at the most inclusive level of the section as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import {
ContextService,
StreamService,
provideContextService,
provideStreamService
} from '@webkrafters/ng-eagleeye';
import type { State } from './state';
const localState = { name: { first: '', last: '' } };
type LocalState = typeof localState;
const selectorMap = {
firstName: 'name.first',
lastName: 'name.last'
} as const;
type MyStreamService = StreamService<LocalState, typeof selectorMap>;
const contextRef = new InjectionToken<ContextService<LocalState>>();
@Component{
providers: [
...,
provideContextService({
attrs: { value: localState },
ref: contextRef // <- assign custom reference handle so as not to override access to root ContextService.
}),
provideStreamService({
contextRef, selectorMap
}), // will stream the contextRef
...
],
...
}
export class DemoComponent implements OnDestroy {
// injects global context service if provided
globalContextService = inject<ContextService<State>>( ContextService );
// injects referenced local context service
localContext = inject<ContextService<LocalState>>( contextRef );
// injects StreamService provided above
streamService = inject<MyStreamService>( StreamService );
data : MyStreamService["data"];
currentState = signal( null as unknown as LocalState );
unsubscribe : ()=>void;
constructor() {
this.data = this.streamService.data;
this.unsubscribe = this.localContextService.store.subscribe(
'data-updated', () => this.currentState.set(
this.localContextService.store.getState()
)
)
}
ngOnDestroy() {
this.unsubscribe();
}
updateFirstName( e: KeyboardEvent ) {
const input = e.target as HTMLInputElement;
this.streamService.setState({
first: { name: input.value }
});
}
writeToGlobalState( e: KeyboardEvent ) {
const input = e.target as HTMLInputElement;
this.globalContextService.store.setState({
a: { b: { c: input.value } }
});
}
}This Demo component creates a limited context along with a stream strictly for its own and its children's consumption while still maintaining direct access to the global ContextService (assuming that the global context service exists).
A provided Angular Eagle Eye context service can be referenced or injected through its constructor
ContextService. To provide it a custom reference, add a ref property. See more on this here.Note: While the Demo Component retained access to the globally provided ContextService, globally provided ContextService is not a dependency for scoped contexts.
Joining the Angular Eagle Eye Change Stream
See StreamService overview hereAngular Eagle Eye change stream is a reactive store whose data are automatically changing to reflect most recent changes affecting them.
We join the Angular Eagle Eye change stream by linking the Angular Eagle Eye
ContextService to a StreamService.The
StreamService wires up the context change stream to your consumer component.Streaming embodies the "set-it-and-forget-it" paradigm. Just set up a list of property paths to state slices to observe (see Selector Map). The context takes care of the rest.
The following is a sample:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { ContextService, provideStreamService } from '@webkrafters/ng-eagleeye';
import type { State } from './state';
const selectorMap = { year: 'a.b.x.y.z[0]' } as const;
type MyStreamService = StreamService<State, typeof selectorMap>;
@Component({
providers: [
provideStreamService({
selectorMap
}) // will stream any closest available non-custom referenced ContextSevice higher in DI chain by default
],
...
})
export class SomeComponent {
streamService = inject<MyStreamService>( StreamService );
data : MyStreamService["data"];
constructor() {
this.data = this.streamService.data;
}
onKeyDown( e: KeyboardEvent ) {
const input = e.target as HTMLInputElement;
this.streamService.setState({ a: { b: { c: input.value } } });
}
}