0

Requirement

There is some (for arguments sake) “global” application state that I am interested in injecting into components.

Each candidate component should receive an immutable snapshot of the state as it existed at the time that its constructor was invoked (for absolute clarity, the state snapshot that is injected into each component’s constructor must not change when the global state changes).

Constraints

I cannot (and do not wish to) use a root-level service or global constant from which components request a state snapshot. Such a solution would require that a component must explicitly request a state snapshot (from the injected service or global constant) from within its constructor, because if it attempted to retrieve it later in its lifecycle, the state might have changed and no longer be relevant to it.

I want to avoid having to declare an injected service locally within each client component’s providers array. This is unnecessarily burdensome. Clients should be able to simply inject a type (or injection token) and receive a state snapshot.

Problem

Although an injection factory method seemed on the surface to be an obvious solution (it would copy the global state and return it to the injector, which would in turn pass it to the component’s constructor), the factory is only invoked once (for each level in the injection hierarchy for which a provider has been configured). I understand that this is by design, however I think that there is a good use-case for the functionality I have described.

What would potentially work is an injection factory implementation similar in concept to Angular pure and impure pipes, where a factory (or potentially any injection configuration) could be declared “impure”, which would result in a new instance being injected into every dependent component.

Surely there is a way to do this?

2 Answers 2

0

I would create a service that holds the state and that updates the state when needed.

Inject that service in the components.

The service contains a method that returns a copy of the current state, that method can be called in the components constructors og NgOnInit methods.

If you later find that you need some components to be able to react on updated states then you can make the service observable and only listen in those components that requires updates.

Services in Angular 2+ are shared between all components that have them injected.

1
  • Thanks for the input, Bent. The problem with that solution is that it invites usage patterns that break state consistency. The state that is injected into each component MUST be a snapshot of the global state as it was when the component's constructor was invoked. That state may change outside of the constructor, and delegating responsibility for retrieving state reliably and consistently to client components is not ideal. I am concluding that such a pattern is not currently possible to implement within Angular. Commented Nov 21, 2018 at 17:19
0

Take a look at the publish / Subscribe pattern (and eventually the library RxJs).

It would allow you to expose (export) the global state as a information source (the "publisher") and each component which is interested in the state can now subscribe. As a result each time the state changes (and publishs a new "version") all subscribers are informed about the change and can react to it.

Be aware, your publisher should provide the current state to each new subscriber (a BehaviorSubject in RxJS). If not, then the subscriber will only be informed about CHANGES, but not about the current state when subscribing.

As soon as a component is not interested any more about the state, it could unsubscribe. For example if a component is only interested in the state when the component is initialized, then the component would unsubscribe as soon as it gets the first data from the observable.

Be aware:
Most Publish/Subscribe Solutions in JavaScript/TypeScript work like that, that they store a callback function of the subscriber in the Publisher. As a result, when the subscriber is long dead (the component destroyed and removed by the garbage collection), the "function" will still have a reference (from the publisher) and will NOT be removed. That means it will STILL BE EXECUTED, even if the component is gone for good.
Threrefore do not forget to unsubscribe in the clean up (ngOnDestroy) of your angular component.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.