What this prompt does
This prompt builds a [feature_name] in Angular [angular_version] that demonstrates exactly when to use Signals versus RxJS. It puts signal-based state behind [signal_use_cases] (simple synchronous state) and RxJS behind [rxjs_use_cases] (async streams and complex transformations), then shows the conversion patterns with toSignal() and toObservable() including proper cleanup.
The structure works because the wrong choice between signals and observables shows up later as change-detection pain. It builds computed signals deriving from [computed_examples], uses effect() for side effects like logging and localStorage sync, applies a signal store via [store_approach] for shared state, and includes a decision-framework flowchart — "Should I use Signal or Observable?" — plus a performance comparison for [perf_scenario]. Complete component code shows both approaches side by side.
What makes the feature genuinely instructive is that it does not pick a winner. By implementing [signal_use_cases] with signals and [rxjs_use_cases] with RxJS in the same [feature_name], it shows the two systems coexisting the way they actually do in real Angular apps. The conversion utilities and the signal store via [store_approach] then demonstrate how shared state flows between them cleanly, so the team learns the boundary by seeing it rather than memorizing a rule.
When to use it
- You are building a reactive Angular feature and unsure where signals end and RxJS begins.
- You want signal-based state for simple synchronous cases like
[signal_use_cases]. - You need RxJS for async streams like
[rxjs_use_cases](WebSockets, polling, debounced search). - You need clean conversion between the two with toSignal() and toObservable().
- You want a shared signal store via
[store_approach]for cross-component state. - You want a decision framework so the team picks the right tool consistently.
Example output
Expect a worked feature with side-by-side code: signal-based state for [signal_use_cases], RxJS streams for [rxjs_use_cases], toSignal() and toObservable() conversion patterns with cleanup, computed signals from [computed_examples], effect() usage for side effects, a [store_approach] signal store, a decision-framework flowchart, and a performance comparison for [perf_scenario]. It is built to teach the boundary, not just to ship one feature.
Pro tips
- Keep
[signal_use_cases]to genuinely synchronous state (toggles, filters, pagination); signals shine there and avoid zone.js overhead. - Leave
[rxjs_use_cases]async work — WebSockets, polling, debounced search — on RxJS rather than bending signals to fit streams. - Use toSignal() at the boundary where an async stream feeds template state, and clean up subscriptions so nothing leaks.
- Lean on computed signals for derived values like
[computed_examples]instead of recomputing them manually in the template. - Reserve effect() for true side effects (logging, localStorage sync); do not use it to derive state that computed should handle.
- Use the decision flowchart as a team convention so the signal-versus-observable choice is consistent, not ad-hoc per developer.
- Put shared cross-component state in a
[store_approach]signal store rather than passing signals through many layers of inputs. - Always clean up subscriptions when converting with toSignal(), so a stream feeding template state does not leak when the component is destroyed.