Chapter 7 — Centralize Filtering and Display Derivation in the Pipeline
Filtering, sorting, and display labels often begin as small template decisions. In Chapter 7 of the SDuX Vault tutorial, those rules move into a service-owned pipeline so every consumer receives the same eligible, sorted
Filtering, sorting, and display labels often begin as small template decisions. In Chapter 7 of the SDuX Vault tutorial, those rules move into a service-owned pipeline so every consumer receives the same eligible, sorted, display-ready collection.
The component still owns presentation concerns such as selection and editor feedback. The service registers one pure filter and three ordered reducers, then exposes the committed FeatureCell State for the UI to render.
Key takeaway: If multiple views need the same data rule, apply it once in the pipeline instead of recreating it in each template.
Why Cross-View Data Rules Belong in the Pipeline
A template is a convenient place to write a quick condition or concatenate two fields. It is a poor place to establish a rule that several screens must share. Once one view filters incomplete records, another sorts them, and a third translates a boolean into a label, the application no longer has one presentation of its data. It has several local interpretations that can drift.
Chapter 7 draws a clean boundary. Resolve produces the incoming candidate collection. Merge combines the current committed State with the resolved candidate when the update requires it. Filters refine the candidate, and Reducers compute the finalized candidate State. Only the result of that pipeline becomes the value observed by the component.
This ordering makes the intent legible. The filter decides which records are eligible for this feature view. The reducers decide how eligible records are ordered and which display-only fields should be available to every consumer. The template reads the result instead of becoming another data-transformation layer.
Refining Candidates with a Pure Filter
The tutorial uses a deliberately small teaching predicate: remove a character whose last name is exactly unknown. The point is not that every incomplete record should disappear in a production system. The point is that eligibility is explicit, named, and reusable.
The filter receives a candidate collection and returns a new collection. It does not edit the input array, write storage, fetch data, or decide how the component should render the result. Those constraints make the rule easy to test and keep it safe to place in the Filters stage.
// example.filter.ts
import { FilterFunction } from '@sdux-vault/shared';
import type { StarWarsCharacter } from './star-wars-character.shape';
/**
* Removes characters whose last name is exactly `"unknown"` without mutating the candidate collection.
* @param characters - Candidate character collection entering the Filter stage.
* @returns A new collection containing every character with a known last name.
*/
export const removeUnknownLastNameFilter: FilterFunction<
readonly StarWarsCharacter[]
> = (characters) => characters.filter(({ lastName }) => lastName !== 'unknown');
⚠️ Warning: A teaching predicate is not automatically a domain policy. In a real feature, a filter might encode authorization, active status, or validated eligibility. Preserve the raw data elsewhere when the application must correct or audit incomplete records.
Composing Ordered Reducers Without Mutation
After filtering, Chapter 7 applies three reducers in a deliberate order. The first derives a force-sensitive display label. The second clones and sorts the collection by last name. The third derives a reusable full name. Each reducer owns one rule, and each receives the result of the previous reducer.
The order matters even though the operations are individually simple. A reducer should operate on the already refined candidate, not repeat filtering logic. The sorting reducer should return a reordered copy, not mutate the collection that entered the stage. The full-name reducer can then rely on the stable name fields and add the display value that every view needs.
| Stage | Operation | Result |
|---|---|---|
| Filters | Remove ineligible candidates | Four retained characters |
| Reducer 1 | Derive force-sensitive display | Each record has a Yes or No label |
| Reducer 2 | Clone and sort by last name | Obi-Wan, Leia, Luke, Darth |
| Reducer 3 | Derive the full name | Every record is display-ready |
This composition also gives each transformation a narrow test surface. You can verify that a helper returns a new array, that sorting does not change its input, and that derived fields match the raw values without mounting the Angular component.
Deriving Display Fields Before Rendering
The raw character shape contains name, lastName, and isForceSensitive. The committed tutorial State also contains fullName and forceSensitiveDisplay, both derived by reducers. That distinction keeps domain data and display-ready values visible without forcing every consumer to repeat the same string composition or boolean translation.
Trace the seed collection through the stages. Chewbacca enters with a last name of unknown and is removed by the filter. Leia remains eligible, receives a force-sensitive display value, participates in the last-name sort, and receives Leia Organa as her full name. The final four-record collection is the value committed for the component to display.
What changed in the template? It now reads reducer-derived fields directly. It no longer decides whether a record is eligible, concatenates names, translates booleans, or sorts the collection during rendering.
Keeping the Component Focused on Presentation
Moving transformation rules into the pipeline does not mean the component becomes passive. It still owns presentation state such as the selected identity, editor mode, form values, confirmation state, and feedback. Those values describe what the current view is doing, not what the shared feature collection means.
The service remains the authority for pipeline registration and committed State. The component consumes the service's reactive State and renders it. That ownership boundary prevents a second copy of filtering or sorting logic from appearing in a different view, and it lets a future consumer use the same display-ready fields without knowing how they were derived.
The same principle makes the next tutorial step easier to reason about. Chapter 8 can turn a filter into a controlled failure source while the component continues to observe the resulting State and error information. The pipeline rule remains explicit instead of being hidden inside a template expression.
Verifying the Committed Collection
Run the completed example and verify the result at the boundary the user sees. Chewbacca should be absent. The remaining records should be sorted by last name. Every visible record should contain both derived display fields, while the source views make the filter and reducer functions inspectable.
Then verify the transformation contract independently: filters and reducers return new collections, their inputs remain unchanged, and the registration order matches the intended data flow. Those checks are more valuable than a screenshot because they protect the rule when another view or future update reuses the same FeatureCell.
⚠️ Warning: Do not infer pipeline behavior from an empty view. If a record is missing, inspect the candidate and the registered transformation that could have removed or changed it. Keep the eligibility rule and display derivation named and testable.
Deeper Dive
Work through the Angular Chapter 7 tutorial, then compare the Filters and Reducers documentation. The complete pipeline specification explains how these stages fit into the broader processing flow.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.