Inputs, Outputs, and State: Clear Data Ownership In short: Data flows down through , events flow up through , and anything only one component cares about stays in a local . Get this right and most state bugs never happen. Our Dairy Logistics app now has components for layout, templates for rendering, directives for behaviour, and services for business rules. The last piece is how these blocks talk to each other without turning into a tangle. The hardest bugs in a large front end are rarely rendering errors. They are ownership errors — a component quietly changing data it does not own, or failing to tell anyone that something happened. Data flows down: An input is a component's public API. It declares the shape of data the component needs from its parent. A child cannot modify a signal input — returns a read-only signal. This is not a convention you have to remember; the type system enforces it. Let's build the , using the directive from the previous lesson. The component owns the structure; the directive owns the warning colours. means the parent must supply it — forget, and the build fails. makes it optional with a sensible fallback. Both are marked , which the style guide asks for on anything Angular initialises: inputs, outputs, models, and queries. Local state: the component's private memory Not every value needs to come from a parent or a service. Sometimes a component just needs to remember something about itself: is this form open? what has the user typed but not submitted? That is local state , and it belongs in a plain writable signal. Keeping local means the dashboard's state never fills up with UI trivia. Events flow up: If a child cannot change its inputs, and its local state is private, how does it tell the system that the operator saved a log? It asks its parent. Name outputs after what happened , not what you want the parent to do. , not . The child reports; the parent decides. Two-way when it genuinely is: Occasionally a value really does belong to both sides — a search box, a selected item, an expanded panel. Pairing an with a matching for this is boilerplate. does both: Use sparingly. Most of the time one-way data plus an event is clearer about who owns what. Assembling the module The is the coordinator. It holds the master state, passes it down, and listens for events coming up. Notice in the update. A new object, not an edit in place — the rule from the first lesson, applied. "But I thought a child could write to an input if it was an object" This belief is stubborn because in older Angular it was technically true and frequently done . With , nothing stopped a child from writing . The parent's object changed, the screen usually updated, and it looked like a feature. Two things changed. First, signal inputs are read-only. does not compile. The API removed the easy version of the mistake. Second, the object escape hatch is now a silent bug rather than a working shortcut. You can still reach through an object input and mutate a property: Under Angular 22's default , the parent's signal still holds the same object reference, so nothing is notified . The parent's own card does not update. Any sibling reading the same tanker does not update. The value in memory and the value on screen have quietly diverged, and whichever component happens to re-render next for an unrelated reason will suddenly show the "new" number — which is why this class of bug gets reported as "the dashboard is randomly wrong". The fix is the ownership rule, not a cleverer write: the child emits, the parent updates its own signal. Cheat sheet The data is… Put it in Example --- --- --- Given by the parent, read-only here / Something that happened, parent must react Genuinely owned by both sides on a search box Only this component's business Derived from other reactive values Needed by unrelated components a service Recap: Chapter 1 Data flows down through read-only signal inputs; events flow up through . Local UI state stays local. A dashboard's state should not know whether a form is expanded. is for genuine two-way values , and should be rare. State lives as high as it must and no higher — parent component, or a service when unrelated components need it. Never mutate through an input. Under the default it does not notify anyone, and the screen silently drifts from the data. We have built a working slice of the tanker intake module: a card, a warning directive, a pricing service, a form, and a coordinator. Every later chapter refactors this same code. One thing left before Chapter 2. Everything above is current Angular — and if you ask an AI assistant for help with it today, there is a good chance it will hand you Angular 15. Let's fix that first.