GitHub package.json versionTypeScriptNPM
GitHub package.json versionTypeScriptNPM
Latest

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-eagleeye

Creating the Angular Eagle Eye store

Two services are provided for this purpose depending on need.
  1. ContextService: the core applicaton state resides here. Use the provideContextService(...) to make this service available to the Angular DI system. More on this here.
  2. 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.
state.ts
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:
demo/demo.ts
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 here
Angular 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:
stream-usage/stream-usage.ts
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 } } }); } }