<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Kobi Hari on Medium]]></title>
        <description><![CDATA[Stories by Kobi Hari on Medium]]></description>
        <link>https://medium.com/@kobihari?source=rss-5c9b8c556791------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*WQ2x_cgnerjH0PgXOOQHsA.jpeg</url>
            <title>Stories by Kobi Hari on Medium</title>
            <link>https://medium.com/@kobihari?source=rss-5c9b8c556791------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 02:24:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@kobihari/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[A Better way to build Angular Components: From Inputs to Composition]]></title>
            <link>https://medium.com/@kobihari/stop-creating-angular-component-monsters-ecb8a8852477?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/ecb8a8852477</guid>
            <category><![CDATA[composition]]></category>
            <category><![CDATA[web-components]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Tue, 07 Apr 2026 14:17:23 GMT</pubDate>
            <atom:updated>2026-04-07T14:21:35.520Z</atom:updated>
            <content:encoded><![CDATA[<h4>Building Scalable UI with the Composite Components Pattern</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TCsW7ULDa0yFtNlZqG-COw.png" /></figure><p>You are building a reusable component. You start with a simple, elegant component — maybe a basic expander — that fits a single use case. But as requirements grow, so does the component.</p><p>You add more and more inputs, and before you know it, you’ve created a <strong>“monster”</strong> — a complex piece of code packed with features, customization options, and countless inputs.</p><p>There’s a better way.</p><h3>The Trap of “Input Overload”</h3><p>When we want to add a new feature, the most common instinct is to add another input() . For example, if you want your expander’s header to be clickable to toggle the content, you might add</p><pre>@Component({<br>  ...<br>  selector: &#39;app-expander&#39;<br>  ...<br>})<br>export class ExpanderComponent {<br>  ...<br>  readonly useHeaderAsToggle = input(false);<br>  ...<br>}</pre><p>However, this approach quickly leads to several problems:</p><ul><li><strong>Maintainability Nightmares:</strong> You end up with components that are 1,000 lines long, filled with if statements and <strong>spaghetti code</strong> that is nearly impossible to understand. Even for this simple example you need conditional styling for clickable headers, conditional event handlers, and perhaps conditional markup.</li><li><strong>Unreadable HTML:</strong> If your component supports 50 features, the consumer might have to manage 50 different inputs in their template, making the HTML impossible to read.</li><li><strong>Poor Logic Separation:</strong> Features that belong to a sub-part (like the header) are being managed by the parent (the expander), which doesn’t make architectural sense.</li></ul><p>To demonstrate the last point — look at this code:</p><pre>&lt;app-expander [useHeaderAsToggle]=&quot;true&quot;&gt;<br>  &lt;span expander-header&gt;The Composite Components Pattern&lt;/span&gt;<br>&lt;/app-expander&gt;</pre><p>The behavior applies to the <strong>header</strong>…<br>but the configuration sits on the <strong>parent</strong>.</p><p>So when reading the template, you’re forced to “jump” between elements to understand what’s going on.</p><p>That’s a design smell.</p><h3>What are Composite Components?</h3><p>The <strong>Composite Components</strong> pattern shifts the focus from “packing features in” to <strong>composing features together</strong>. The idea is simple:</p><ul><li>The main component stays small</li><li>Features live in separate units (directives / sub-components)</li><li>Consumers combine them as needed</li></ul><h3>Practical Example: The Expander Header Toggle</h3><p>Instead of adding another input, we move the behavior into a directive.</p><pre>@Directive({<br>  selector: &#39;[expander-header][toggle]&#39;, // Requires both attributes to apply<br>  host: {<br>      &#39;[style.cursor]&#39;: &#39;&quot;pointer&quot;&#39;, <br>      &#39;(click)&#39;: &#39;onClick()&#39;<br>  }<br>})<br>export class ExpanderHeaderToggleDirective {<br>  // Inject the parent expander component to access its logic<br>  private expander = inject(ExpanderComponent, { optional: true });<br><br><br>  // Handle the click event to call the expander&#39;s toggle method<br>  onClick() {<br>    this.expander?.toggle();<br>  }<br>}</pre><p>Usage Becomes:</p><pre>&lt;app-expander&gt;<br>  &lt;span expander-header toggle&gt;The Composite Components Pattern&lt;/span&gt;<br>&lt;/app-expander&gt;</pre><h4>What Did We Gain?</h4><ul><li>No new inputs</li><li>No changes to the main component</li><li>Feature is fully encapsulated</li><li>The expander stays clean and focused.</li></ul><h3>Real-World Inspiration: Angular Material</h3><p>This isn’t a new or niche pattern; it has been used by <strong>Angular Material</strong> since its inception.</p><ul><li><strong>&lt;mat-form-field&gt; : </strong>This component doesn’t have a massive list of inputs for labels, hints, or icons. Instead, you <strong>compose</strong> it using directives like matInput, &lt;mat-label&gt;, and matSuffix.</li><li><strong>&lt;mat-card&gt;:</strong> A card is a package of sub-components like &lt;mat-card-header&gt; and directives like matCardAvater . This allows the main card component to have very few inputs while remaining incredibly flexible.</li></ul><h3>Why You Should Use This Pattern</h3><ol><li><strong>Encapsulation:</strong> Every feature lives in its own file.</li><li><strong>Flexibility:</strong> Users can mix and match exactly which features they need for a specific instance.</li><li><strong>Clean APIs:</strong> Your main component doesn’t get cluttered with irrelevant inputs.</li><li><strong>Standardization:</strong> This pattern is becoming the standard for modern component libraries and is heavily utilized in newer packages like <strong>Angular Aria</strong> (often paired with headless component patterns).</li></ol><p>By adopting composite components, you can build a robust library where features <strong>play nicely together</strong> without turning your codebase into a monster. In the long run, this allows you to maintain the same codebase across many different projects with ease.</p><h3>What’s next</h3><p>If this resonates, I go much deeper into this pattern — including advanced composition techniques and real-world examples — in my new Udemy course, <a href="https://www.udemy.com/course/building-reusable-components-in-angular-the-missing-guide/?couponCode=MISSING_GUIDE_2603"><em>Building Reusable Components in Angular — The Missing Guide</em>.</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/250/1*oUlBH9r_oDt1xDoa2YcsKg.png" /><figcaption>Building Reusable Components in Angular — The Missing Guide</figcaption></figure><p>It’s a hands-on deep dive into composable components, content projection, templates, and the patterns behind real-world component libraries.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ecb8a8852477" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reusable Validation in Angular’s Signal Forms]]></title>
            <link>https://medium.com/@kobihari/reusable-validation-in-angulars-signal-forms-d3cf742a54cc?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/d3cf742a54cc</guid>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <category><![CDATA[reuse]]></category>
            <category><![CDATA[code-reuse]]></category>
            <category><![CDATA[angular-signal-forms]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Sun, 01 Feb 2026 10:36:12 GMT</pubDate>
            <atom:updated>2026-02-01T10:51:21.207Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CIlES-e41HaxgoBF7FBmLQ.png" /></figure><p>I Hate repeating myself. <br>Again…<br><strong>I Hate repeating myself.</strong><br>Especially in code.</p><p>Repeating logic is one thing we all know is bad. In software, they train us to <em>encapsulate</em>, <em>reuse</em>, <strong>to abstract</strong>. Our techers even give us achronyms so the lesson sticks — DRY (<strong>D</strong>on’t <strong>R</strong>epeat <strong>Y</strong>ourself… don’t repeat yourself). Every modern paradigms since OOP has tried to solve the same problem: how to package logic so it can be reused — with classes, functions, closures… whatever.</p><p>And yet, when working with Angular’s Reactive Forms, I keep running into the same situation: <em>repeating validation logic for the same combinations of fields</em>. Literal copy-paste. Over and over again.</p><h3>A Familiar Case</h3><p>Take this example. in one of my projects, I have many (many…) different forms where two fields always appear together:</p><pre>readonly status: TaskStatus; // &#39;upcoming&#39; | &#39;ongoing&#39; | &#39;completed&#39;;<br>readonly dueDate: string; // ISO date string</pre><p>And the logic is always the same:</p><ul><li>status is required</li><li>If status === &#39;completed&#39;, dueDate should be read-only</li><li>Otherwise, dueDate must be a date in the future</li></ul><p>Now, technically, I <em>could</em> create a nested control that encapsulates this logic and reuse it. But that comes with a cost: it pollutes the model with structure that exists purely for technical reasons.</p><p><strong>What I really want is this:</strong></p><ul><li>Keep the form model <strong>flat</strong></li><li>Apply <strong>cross-field validation</strong></li><li>Reuse the logic</li><li>No duplication</li></ul><h3>Reusable Schemas in Signal Forms</h3><p>Signal Forms introduces the concept of a <strong>schema</strong>.<br> A schema doesn’t describe just validation — it describes <em>form logic</em>. Validation, metadata, readonly rules — it all lives under the same umbrella.</p><p>(In the example above, “readonly when completed” isn’t validation per se, but in Signal Forms it’s still part of the schema.)</p><p>So how do we make that logic reusable?</p><h4>Step 1: Define a focused Interface</h4><p>First, we define an interface that represents only the fields involved in the shared logic:</p><pre>export interface TodoItem {<br>  readonly status: TaskStatus;<br>  readonly dueDate: string; // ISO date string<br>}</pre><p>Important detail:<br> The form model does <strong>not </strong>need to <strong>explicitly </strong>declare that it implements this interface.</p><p>TypeScript uses structural typing. If a form has these two properties with the correct types, it implicitly matches this interface — whether it “knows” it or not.</p><h4>Step 2: Define the Schema</h4><p>Now, let’s define the schema as a reusable function. We do it using the schema function.</p><pre>export function todoItemSchema() {<br>  return schema&lt;TodoItem&gt;((path) =&gt; {<br>    required(path.status);<br>    readonly(path.dueDate, <br>        ctx =&gt; ctx.valueOf(path.status) === &#39;completed&#39;);    <br>    validate(path.dueDate, (ctx) =&gt;<br>        new Date(ctx.value()).valueOf() &gt; Date.now()<br>          ? null<br>          : { <br>              kind: &#39;dueDateInPast&#39;, <br>              message: &#39;Due date must be in the future.&#39; <br>            },<br>    );<br>  });<br>}</pre><p>This schema defines three rules:</p><ol><li>The status field is required</li><li>The dueDate field is readonly if the value of the status field is equal to completed</li><li>The dueDate field value has to be in the future.</li></ol><p>One subtle but important detail:<br> The third rule only applies when the field is <strong>not</strong> read-only. In Signal Forms, read-only fields do not participate in validation.</p><h4>Step 3. Reusing the schema</h4><p>Now let’s say we have a larger model that includes these two fields, plus others:</p><pre>export interface UserStory {<br>    readonly displayName: string;<br>    readonly assignedTo: string;<br>    readonly estimationPoints: number;<br>    readonly reviewer: string;<br>    readonly status: TaskStatus;<br>    readonly dueDate: string; // ISO date string<br>}</pre><p>And we create a writeable signal of this type:</p><pre> readonly story = signal&lt;UserStory&gt;({<br>    displayName: &#39;Implement Signal Forms&#39;,<br>    assignedTo: &#39;Alice Johnson&#39;,<br>    estimationPoints: 5,<br>    reviewer: &#39;Bob Smith&#39;,<br>    status: &#39;ongoing&#39;,<br>    dueDate: &#39;2024-07-15&#39;<br>  });</pre><p>Now we wrap it with a signal form:</p><pre>protected readonly storyForm = form&lt;UserStory&gt;(this.story, path =&gt; {<br>    required(path.displayName);<br>    required(path.assignedTo);<br>    max(path.estimationPoints, 10);<br>    required(path.reviewer);<br>}</pre><p>We have added some validation rules to all the <strong>other</strong> fields.</p><p>We can use the apply function to <strong>apply </strong>our reusable schema to this form — literally adding all its rules to the rules that already exist in this forms schema:</p><pre>protected readonly storyForm = form&lt;UserStory&gt;(this.story, path =&gt; {<br>    required(path.displayName);<br>    required(path.assignedTo);<br>    max(path.estimationPoints, 10);<br>    required(path.reviewer);<br><br>    // one line - all rules applied<br>    apply(path, todoItemSchema()); <br>  });</pre><p>That’s it.</p><p>No nesting, <br>No duplication, <br>Same logic reused everywhere.</p><h3>Final Thoughts</h3><p>This feature isn’t flashy — and that’s exactly why I like it. It reflects what Signal Forms does well</p><blockquote><strong>Reusablity is at the core of its architecture</strong>.</blockquote><p>It’s built for reusablity from the ground up.</p><p>And this is just one example. There are many other places where Signal Forms quietly makes reuse easier and cleaner. I cover most of them in my course <a href="https://www.udemy.com/course/modern-angular-with-signals-the-missing-guide/?couponCode=MISSING_GUIDE_2601"><strong><em>Modern Angular with Signals</em></strong></a>, where I spend about three hours just on Signal Forms (That’s how much I love this new feature).</p><p>It’s obvoius that the guys at the Angular team have put a lot of thought into the signal forms feature. What came out is a work of art.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d3cf742a54cc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Connecting Signal Forms to a Signal Store]]></title>
            <link>https://medium.com/@kobihari/connecting-signal-forms-to-a-signal-store-39dabd69b888?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/39dabd69b888</guid>
            <category><![CDATA[angular-signals]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[signal-forms]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <category><![CDATA[ngrx-signalstore]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Wed, 31 Dec 2025 12:55:18 GMT</pubDate>
            <atom:updated>2025-12-31T12:55:18.742Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gV22eDkrkdB3u6pqxv0ttQ.png" /><figcaption>Connecting Signal Forms to Signal Stores</figcaption></figure><p>In my courses, I get this question a lot:</p><blockquote>“How do I connect Signal Forms to a Signal Store”</blockquote><p>In a Signal Store, (as in most services) state is exposed as <strong>read-only signals</strong>.<br> That’s intentional. Consumers can read, but updates must go through store methods.</p><p>Signal Forms, on the other hand, expect a <strong>writable signal</strong>. They assume they are allowed to call set() freely.</p><p>So things dont line up.</p><h3>Why direct binding is a problem</h3><p>Today, NgRx signal store has a withLinkedState feature. This feature allows <a href="https://ngrx.io/guide/signals/signal-store/linked-state#explicit-linking">you to add a writeable signal to the core state</a>, so it can be updated <strong>directly</strong>.</p><p>That’s problematic. If we pass a service writeable signal <strong>directly </strong>to a form, we immediately lose something important.</p><p>The form can now:</p><ul><li>Mutate state directly</li><li>Bypass store methods</li><li>Skip validation, normalization, or multi-field coordination</li><li>Generate state transitions the store never “approved”</li></ul><p>Sometimes that’s unacceptable.</p><p>Maybe the form <strong>edits only part</strong> of the state… Maybe updating one field <strong>requires updating others</strong> to keep the model consistent… Maybe updates must be <strong>atomic</strong>…</p><p>We also lose the ability to use other store extensions that rely on their own updaters, for example, the withEntities custom feature depends on the updateEntity updater. So if you want to add an entity <strong>and</strong> be able to edit it in a form — that would be a problem.</p><p>Another example is withDevtools from <a href="https://ngrx-toolkit.angulararchitects.io/">The NgRx toolkit</a> . It allows inspecting store state using browser devtools, but it requires updates to go through updateState instead of patchState, so metadata about the change can be recorded.</p><p>If the form could directly modify your state… If, <strong>theoretically</strong>, the state could be exposed as a writeable signal, that updater function would be bypassed entirely.</p><p>So what we’re really looking for is this:</p><blockquote>we want the form to rely on model state held in the store, while still controling how updates flow back to the store. <br><strong>The store must stay in charge</strong>.</blockquote><h3>Duplex Unidirectional Flow</h3><p>Instead of <strong>two-way binding</strong> we want two <strong>unidirectional </strong>flows.</p><ol><li>When the <strong>store </strong>state changes, the new state should flow into the form so the fields reflect it — that’s the easy part.</li></ol><p>2. When the <strong>form </strong>state changes, the new value should flow back into the store <strong>through custom logic that we control </strong>— That’s the tricky part.</p><h3>The easy case (and why it’s not always enough)</h3><p>If the store should update only when the user <strong>submits </strong>the form, the solution is straightforward.</p><ul><li>You keep the form model local to the component holding the form.</li><li>On submit, you call the store method.</li></ul><p>This is exactly where linkedSignal shines — something I covered in a <a href="https://medium.com/@kobihari/making-a-read-only-signal-editable-in-your-component-22a5d8cbd22f">previous article</a>.</p><p>But there’s another scenario I keep seeing.</p><h3>The harder case: continuous sync, controlled updates</h3><p>Sometimes, you <em>do</em> want the form and the store to stay in sync while the user types.</p><p>But still:</p><ul><li>Updates must go through store methods</li><li>Update logic must remain explicit</li><li>No hidden mutation paths</li><li><strong>No effects </strong>quietly “watching” and reacting</li></ul><p>That combination doesn’t come built in.</p><p>So I built a small utility for it.</p><h3>Introducing: Projected signal</h3><p>If you want to see the code, there’s a demo app in this <a href="https://github.com/kobi2294/fun-with-projected-signals">GitHub repository</a></p><p>The core idea is simple:</p><ul><li><strong>Reading</strong> comes from the store</li><li><strong>Writing</strong> goes back to the store</li><li>To the outside world, it still behaves like a writable signal</li></ul><p>I call this a <strong>projected signal</strong>.</p><p>It “projects” store state <strong>outward </strong>as a signal, while “projecting” updates <strong>inward </strong>through store APIs.</p><p>That separation is the key.</p><h3>What a projected signal looks like</h3><p>A projected signal is defined by two things:</p><ol><li>A computation — how to read from the store</li><li>An update function — how writes are handled</li></ol><pre>readonly projected = projectedSignal({<br>  computation: () =&gt; this.store.xy(),<br>  update: value =&gt; this.store.setXY(value)<br>});</pre><p>The projectedSignal function returns a ProjectedSignal&lt;T&gt; which <strong>extends</strong> WritableSignal&lt;T&gt;. So all practical purposes, it <strong><em>is </em></strong>a WritableSignal.</p><p>But there’s a catch</p><p>This writeable signal <strong>does not store it’s own value.</strong> It assumes entity manages the state and acts purely as a proxy.</p><p>Internally, it wraps the computation in a <strong>computed signal</strong> so it stays up to date. When someone calls set() or update(), the logic is delegated to the provided updater.</p><p>From the store’s point of view, <strong>nothing changed</strong> — all updates still go through explicit methods.</p><p>No mutation.<br> No bypass.</p><h3>Why Signal Forms work with this</h3><p>Signal Forms don’t need to know about stores.</p><p>They only require one thing:<br> a signal they are allowed to write to.</p><p>ProjectedSignal&lt;T&gt; intentionally extends WritableSignal&lt;T&gt;.</p><p>That single design choice is what allows this to work:</p><pre>readonly form = form(this.projected, path =&gt; {<br>  max(path.x, 20),<br>  max(path.y, 20)<br>});</pre><p>The form writes.<br> The projected signal intercepts.<br> The store decides what actually changes.</p><h3>The actual data flow</h3><p>When the user edits the form, the flow is very explicit:</p><ul><li>The Form Updates</li><li>ProjectedSignal.set is called</li><li>The store method is called</li><li>In this specific example: Devtools and logging occurs</li><li>Store state changes</li><li>The projected signal updates</li><li>The form updates</li><li>The UI updates</li></ul><p>And most importantly:</p><p><strong>No Effects</strong></p><p><strong>No Hidden Observers</strong></p><p>Just unidirectional data flow — even during live editing.</p><h3>Why this stays boring (in a good way)</h3><p>This utility doesn’t introduce a new paradigm.</p><p>It doesn’t replace stores.<br> It doesn’t modify forms.<br> It doesn’t add lifecycle hooks or side channels.</p><p>It simply restores a boundary that forms tend to blur:</p><blockquote><strong>Forms </strong>describe user intent. <strong>Stores </strong>decide how state changes.</blockquote><p>A projected signal is just the adapter between the two.</p><h3>Final thought</h3><p>I see this pattern often enough that I wanted it to be explicit, reusable, and boring.</p><p>That’s usually a good sign.</p><p>I’d genuinely love to hear what you think about this approach — <br> especially if you’ve solved this problem differently.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=39dabd69b888" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Did I Miss This After 5 Years: TypeScript’s String Literal Templates]]></title>
            <link>https://medium.com/@kobihari/how-did-i-miss-this-after-5-years-typescripts-string-literal-templates-09d350cfabe9?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/09d350cfabe9</guid>
            <category><![CDATA[string-literal]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[uuid]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Mon, 08 Dec 2025 20:44:13 GMT</pubDate>
            <atom:updated>2025-12-08T20:44:13.551Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rm8fW8qZeFNsrg8iscQavA.png" /></figure><h3>A Simple Search for a UID Turns Into Something Else</h3><p>In one of my latest projects, I started from a clean base and needed a <strong>unique ID generator</strong>. It happened many times in the past, but this time the customer specifically asked to <strong>minimize using open‑source packages</strong>. So I decided to check whether TypeScript had a native way to generate IDs. Surprisingly, it did.</p><p>I discovered the global crypto object. This constant exists in modern JavaScript runtimes but many developers (myself included) barely touched it. Most of us assume anything cryptographic requires a library, but the browser and Node both ship with a built‑in cryptography API capable of generating “crypto-safe” random values.</p><p>Turns out it can also produce secure UUIDs. I found crypto.randomUUID(). So of course, I hovered over the function definition… and that’s when the real surprise hit me.</p><h3>A Surprising intellisense</h3><p>Hovering over the function, I expected the usual: randomUUID(): string</p><p>Instead, VSCode casually shows me this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZR0TKhfEwHhuhy6egsohrA.png" /><figcaption>The return type isn’t just a string</figcaption></figure><p>The return type looks like a template literal from JavaScript , except it’s not a value, it’s a <strong>type…</strong></p><p>How is this even a thing?</p><h3>Putting the Curious Type to the Test</h3><p>Naturally, I had to <strong>poke</strong> it a little. I created a variable with a template type and fed it a matching string.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/753/1*H2izRsdV-8DNcX-jKxKU9g.png" /><figcaption>OK</figcaption></figure><p>TypeScript nodded politely.</p><p>Then I removed a hyphen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oU63e6IMzTlHN0oITdNutQ.png" /><figcaption>ERROR</figcaption></figure><p>Error!</p><p>The <strong>compiler</strong> — not a regex, not a linter — was validating the <em>shape</em> of the string. At compile time.</p><p>This was no longer about UUIDs. This was a whole new door I didn’t know TypeScript even had.</p><h3>What Can Go Inside Those ${} Slots?</h3><p>So then the question was: what can you even put inside these ${} placeholders? Turns out you can put more than I initially expected.</p><p>It starts, with the expected:</p><ul><li>literal strings? sure.</li><li>numbers? works just fine.</li><li>booleans? also valid.</li></ul><p>I tried all three. TypeScript happily converted numbers and booleans to their string forms inside the template.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/824/1*DXEsw__5j0pvguQlKjwCPA.png" /><figcaption>Booleans and Numbers</figcaption></figure><p>It also works with <strong>built‑in string manipulation helpers</strong> like Uppercase&lt;&gt;, Lowercase&lt;&gt;, and Capitalize&lt;&gt;. These let you transform parts of the template. For example, you can enforce that a value always starts with an uppercase letter or that a segment must be uppercase:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mledUqoLNHWFIpCUAG5cXw.png" /><figcaption>String Transforms</figcaption></figure><h3>And for Dessert…</h3><p>I decided to try something else: <strong>what happens if I use unions inside these templates?</strong></p><p>That immediately reminded me of an old annoyance I had when working with CSS types. At the time, I wanted to create a property type that listed <em>all possible border properties</em> in CSS — things like border-top-width, border-right-color, and so on.</p><p>Back then, the only real option was to manually write a giant union of strings or rely on external helpers. Neither approach felt elegant.</p><p>So this time, standing in front of TypeScript’s template literal types, I wondered: <em>can I finally generate that whole family of strings using unions?</em></p><p>Instead of typing each one manually, you write:</p><pre>type BorderSide = &quot;top&quot; | &quot;right&quot; | &quot;bottom&quot; | &quot;left&quot;;<br>type BorderProp = &quot;width&quot; | &quot;style&quot; | &quot;color&quot;;<br><br>type BorderProperty = `border-${BorderSide}-${BorderProp}`;</pre><p>Now you can define a variable of that type and hover over it…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/753/1*0JdKn2v6lF28f_jTDoAkjQ.png" /><figcaption>Union Crosses</figcaption></figure><p>You gotta love Typescript…</p><h3>A Small Conclusion</h3><p>After reading more about it, I found out something almost anticlimactic: <strong>this isn’t new at all</strong>. In fact, template literal types have been part of TypeScript since <strong>version 4.1 — released back in 2020</strong>. So while many readers may already know and use them, somehow… I completely missed them.</p><p>Maybe they never came up in my day‑to‑day work. Maybe I never hovered over the right function signature. Either way, the feature was there all along. But if I missed it, maybe you did too?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=09d350cfabe9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Most Exciting Feature of Angular Signal Forms No One Mentions — Part II]]></title>
            <link>https://medium.com/@kobihari/the-most-exciting-feature-of-angular-signal-forms-no-one-mentions-part-ii-6ef41f8c4f2a?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/6ef41f8c4f2a</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[signal-forms]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Fri, 28 Nov 2025 06:17:26 GMT</pubDate>
            <atom:updated>2025-11-28T07:09:05.432Z</atom:updated>
            <content:encoded><![CDATA[<h3>The Most Exciting Feature of Angular Signal Forms — Part II</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CIlES-e41HaxgoBF7FBmLQ.png" /></figure><p>In the <a href="https://medium.com/@kobihari/the-most-exciting-feature-of-angular-signal-forms-no-one-mentions-844f967ff6db">previous article</a>, I told you how I stumbled into the discovery that Signal Forms don’t just validate — they actually broadcast metadata straight into the UI. min, max, required, length limits… all flowing into components without me adding a single attribute in the template.</p><p>That little surprise left us with a question hanging in the air:</p><p><strong>Can we create our own metadata keys — and make Angular treat them exactly like the built-in ones?</strong></p><p>The short answer is yes.<br> The interesting part is <em>how</em>.</p><p>And to understand that, we need to zoom into something Angular quietly builds for us behind the scenes.</p><h3>The Field State</h3><p>Whenever you create a form, Angular builds a tree of field wrappers called FieldTree. As the name suggests, it mirrors the structure of your form model: each FieldTree holds child FieldTrees — a tree of fields inside a tree of fields.</p><p>But there’s a twist:<br> each FieldTree is <em>also a function</em>.<br> Call it, and you get a FieldState object loaded with signals describing the field’s current state:</p><ul><li>dirty: Signal&lt;boolean&gt;</li><li>touched: Signal&lt;boolean&gt;</li><li>invalid: Signal&lt;boolean&gt;</li></ul><p>…and many more.</p><p>So far, nothing unusual. But inside this object lives something much more interesting — something that unlocks the whole mystery.</p><h3>The Metadata Function</h3><p>The state also includes a function called metadata. You give it one parameter — a “Key” (tell you about it in a sec) and it returns the value of a <strong>metadata property.</strong></p><p>The “Keys” are a little like InjectionToken. Just like inject() returns a value of type T based on a token of type InjectionToken&lt;T&gt;, metadata() returns a Signal&lt;T&gt;based on a MetadataKey&lt;T&gt;. Why Signal? Because field metadata properties can change just like everything else in the form. And we want to be able to react to these changes.</p><p>To summarize — here’s a little code</p><pre>readonly data = signal({x: 1});<br>readonly myForm = form(this.data, path =&gt; {<br>  max(path.x, 10)<br>})<br><br>readonly xFieldTree = this.myForm.x;<br>readonly xState = this.xFieldTree();<br>readonly maxValue = this.xState.metadata(MAX); // Signal&lt;number | undefined&gt;</pre><p>Now maxValue() is yours to display in the template — an automatic hint telling the user what keeps your validator happy.</p><h3>Can I create my own Keys?</h3><p>Of course you can, that’s the whole point of this article.</p><p>You can create your own MetadataKey&lt;T&gt; just like you can create a custom InjectionToken&lt;T&gt;.<br> But there is one complication:</p><p><strong><em>Aggregation</em></strong>.</p><p>To put it simply — Imagine two validators, and both set different <strong>min values </strong>to the same field. The first one sets the min value to <strong>5</strong>, and another sets it to <strong>6</strong>.</p><p>What is the effective <strong>minimum value</strong>? 6, right? Because if the field’s value is 6 or above — both validators are happy. If the field’s value is 5, only one validator is happy, and the other one returns an error. So if you want to present a hint that tells the user what values she may enter in the field so that both validators are happy — this value would have to be the largest of the two.</p><p>But what about a <strong>max value</strong> validator? Now it’s the other way around. If one validator requires a max value of 8 and the other requires max value of 9, then the effective max value is 8. and that’s the value of the <strong>MAX </strong>metadata property.</p><p>So metadata keys need to know <em>how to combine multiple values</em>. This logic is embedded in the key itself. So when you create a new metadata key, you choose a factory method that builds the key with the correct embedded aggregation logic.</p><p>Angular gives you various factory functions to choose from.</p><pre>const MAX_WORDS = minMetadataKey(); // key where the aggregated value is the minimum of all values<br>const MIN_WORDS = maxMetadataKey(); // key where the aggregated value is the maximum of all values</pre><p>And if you want full control there’sreducedMetadataKey where you simply provide your own logic.</p><p>So now you know <strong>how to create metadata property keys</strong>. (or more precisely— an AggregateMetadataKey&lt;T&gt;)</p><p>You also know how to get the effective value of this metadata property for each field.</p><p>Which brings us to the last secret.</p><h3>How do you set these values?</h3><p>To write values into a metadata key, you use the function aggregateMetadata(). It takes 3 parameters:</p><ol><li>The path (representing the field)</li><li>The property metadata Key</li><li>A function that computes the value from the field context</li></ol><p>Why a function? <br>Why does everything have to be a function in <strong>signalForms</strong>? <br>Why can’t they just take a normal value and keep it simple?</p><p>Well… That’s because signals are functions, and metadata needs to be reactive too. And sometimes metadata depends on <strong>other fields</strong>. For example you can set the minimum number of words in one field depending on the value of another field.</p><p>Cool, isn’t it? Even if it’s a bit complex.</p><h3>Writing a Custom Validator with Metadata</h3><p>Say you want a reusable validator called minWords, and you want it flexible enough to accept:</p><ul><li>A simple number, or</li><li>A function that calculates the number based on other fields</li></ul><p>Here’s the signature:</p><pre>export function minWords(<br>  path: SchemaPath&lt;string&gt;, <br>  minValue: number | LogicFn&lt;string, number&gt;) {<br>...<br>}</pre><p>The first parameter is a path that indicates which field should be validated. It has to be a string field (which makes sense if we are going to count the words in this field) — hence SchemaPath&lt;string&gt; — it’s a path that points to a field of type string.</p><p>The second parameter is either a number, or a function that calculates a number from the context of that field.</p><p>inside, before you call the validate function to perform the actual validation, you publish the metadata.</p><p>So your reusable custom validator will look like this:</p><pre>export function minWords(<br>  path: SchemaPath&lt;string&gt;, <br>  minValue: number | LogicFn&lt;string, number&gt;) {<br><br>  aggregateMetadata(path, MIN_WORDS, (ctx) =&gt;<br>    typeof minValue === &#39;number&#39; ? minValue : minValue(ctx)<br>  );<br><br>  validate(path, ctx =&gt; {<br>    // validation logic that either returns undefined or customError<br>  }<br>}</pre><p>And that’s it.</p><p>By the way, if you peek into the source code, you’ll see that the built-in validators (min, required, pattern, maxLength) all follow this exact structure.</p><h3>And The best thing</h3><p>For me, the real magic happens once you start treating <strong>every part</strong> of your field as metadata. Suddenly your forms gain structure, consistency, and a level of reuse that’s hard to unsee once you try it.</p><p>If you want to explore this pattern end-to-end — with real components, a real form, and the full metadata flow — I break it down in my <a href="https://www.udemy.com/course/modern-angular-with-signals-the-missing-guide/?couponCode=MISSING_GUIDE_11">online digital course: <strong><em>Modern Angular with Signals — The Missing Guide</em></strong>.</a> It’s the most complete walkthrough I’ve created so far.</p><p>Honestly, working with the new <strong>Signal Forms</strong> has been a real pleasure. You can feel how much thought went into the design — every piece fits together, every feature has a purpose, and the whole system feels both powerful and elegant. It’s one of those rare additions to Angular that just “clicks” the moment you start building with it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ef41f8c4f2a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Most Exciting Feature of Angular Signal Forms No One Mentions]]></title>
            <link>https://medium.com/@kobihari/the-most-exciting-feature-of-angular-signal-forms-no-one-mentions-844f967ff6db?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/844f967ff6db</guid>
            <category><![CDATA[angular-21]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[angular-signal-forms]]></category>
            <category><![CDATA[angular-signals]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Thu, 20 Nov 2025 17:09:30 GMT</pubDate>
            <atom:updated>2025-11-20T17:09:30.130Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CIlES-e41HaxgoBF7FBmLQ.png" /></figure><h3>It Started with a Weird Compilation Error</h3><p>Angular 21 was just released, and like everybody, I wanted to try out the most exciting feature — <strong>Signal Forms.</strong> I started with the simplest setup I could think of: just one numeric field called rating. I added min and max validators. Nothing fancy.</p><pre>readonly model = signal({<br>    rating: 3<br>  });<br><br>readonly ratingForm = form(this.model, f =&gt; {<br>    min(f.rating, 1);<br>    max(f.rating, 5);<br>  })</pre><p>I created a range slider and added the usual min and max attributes there too (because I wanted the UI to reflect the legal range).</p><pre>&lt;div class=&quot;field&quot;&gt;<br>    &lt;label&gt;Rating&lt;/label&gt;<br>    &lt;div class=&quot;control&quot;&gt;<br>      &lt;input type=&quot;range&quot; min=&quot;1&quot; max=&quot;5&quot; <br>            [field]=&quot;ratingForm.rating&quot; /&gt;<br>      &lt;span&gt;{{ model().rating }}&lt;/span&gt;<br>    &lt;/div&gt;<br>  &lt;/div&gt;</pre><p>Only to discover that Angular simply refused to compile. And I got this strange error:</p><figure><img alt="min attribute is not allowed on nodes using the `[field]` directive" src="https://cdn-images-1.medium.com/max/853/1*zaCoVDQnhiQKXaa3Q21cQg.png" /><figcaption>Setting the ‘min’ attribute is not allowed</figcaption></figure><p>It wouldn’t let me set those attributes at all. I removed them because I had no choice. And that’s when things got strange.</p><h3>When the UI Knows Things You Never Told It</h3><p>With the attributes removed, I expected the range input to fall back to default browser behavior. But instead, the slider automatically used the values from my validators.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/257/1*RPLkMUNDeG8vfYUCsv7XtQ.png" /><figcaption>Range is set “automagically” between 1–5</figcaption></figure><p>Just to be sure it wasn’t a coincidence, I changed the validation range to something unusual like -10 to 10.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/235/1*e0LmWGWZySBbl6te0mmZcw.png" /><figcaption>Range is set from -10 to 10</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/241/1*d48n1-cusHF35bMa5qibdg.png" /><figcaption>“automagically” again</figcaption></figure><p>It still worked. Perfectly. So I opened DevTools to see what was going on. And there it was: the min and max attributes did exist, just not because I set them. The directive had injected them into the DOM.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/453/1*p9mTrlYjNvq42_-E48g0Nw.png" /><figcaption>min and max are set to the correct values</figcaption></figure><p>Somehow, the slider was reflecting validation logic that lived deep inside a function I wrote.</p><h3>The Validator Knows… but How Does the Directive Know?</h3><p>But that raised a deeper question.</p><p>A validator is just a function. It receives a value and returns an error — or doesn’t. The parameters I pass into that validator are hidden inside its closure. So how does the directive know them? How does it extract { min: -10, max: 10 } out of a function call it never sees?</p><p>And if Angular can do this for built‑in validators… can it do it for custom validators too? Could I create a validator that enforces a minimum of 50 <strong>words</strong> and have that “50” become metadata that components can read and use?</p><p>And one last question. If I write my own custom range selection control that is based on marking “stars”, can it also receive this information automatically from the [field]directive?</p><h3>Ding Dong, The ControlValueAccessor is gone</h3><p>With ControlValueAccessorout of the picture, building a custom control became almost effortless. I wanted to test whether schema metadata — like the max value I used earlier—would automatically flow into my own component the same way it did with the range slider.</p><p>All I needed was a component with an <strong>input model</strong> called value</p><pre>export class StarRating {<br>  readonly value = model.required&lt;number&gt;();<br>}</pre><p>That’s already enough for the [field] directive to wire the form control to my component. But I wanted to go further: could a metadata value like max be passed into my component as well?</p><p>So I added an input called max. Since I wanted to allow undefined as a valid state, I defined it like this:</p><pre>export class StarRating {<br>  readonly value = model.required&lt;number&gt;();<br><br>  readonly max = input&lt;number | undefined&gt;(undefined);<br><br>  readonly stars = computed(() =&gt; <br>    Array.from({ length: this.max() ?? 5}, (_, i) =&gt; i + 1));<br><br>}</pre><p>Now stars becomes a computed signal holding an array from 1 to max, letting the template iterate and display filled or empty stars depending on their index and the current value.</p><pre>@for(i of stars(); track i) {<br>    &lt;mat-icon (click)=&quot;value.set(i)&quot;&gt;<br>        @if(i &lt;= value()) {<br>            star<br>        } @else {<br>            star_outline<br>        }<br>    &lt;/mat-icon&gt;<br>}</pre><p>Finally, the big test: would Angular pass the max metadata value into my component automatically? I set the validator to max(f.rating, 7) and… well, the result speaks for itself.</p><pre>export class App {<br>  readonly model = signal({<br>    rating: 3<br>  });<br><br>  readonly ratingForm = form(this.model, f =&gt; {<br>    max(f.rating, 7);<br>  })<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/295/1*SOyH1HNrm6-RXWQQg58fsg.png" /><figcaption>YES!!!</figcaption></figure><p>It worked.</p><h3>Peeking Under the Hood</h3><p>But how does it really work?</p><p>Curiosity won. I opened the Angular source code.</p><p>What I found is that Signal Forms validators don’t just validate — they also publish <strong>structured metadata</strong> onto the field object. Each validator function has two parts:</p><pre>export function max&lt;...&gt;(path: SchemaPath&lt;...&gt;,<br>  maxValue: number | LogicFn&lt;...&gt;) {<br>  // ...<br>  aggregateMetadata(path, MAX, ({state}) =&gt; state.metadata(MAX_MEMO)!());<br>  validate(path, (ctx) =&gt; {<br>    // ...<br>    const max = ctx.state.metadata(MAX_MEMO)!();<br>    // ...<br>    const value = ctx.value();<br>    const numValue = !value &amp;&amp; value !== 0 ? NaN : Number(value); // Treat `&#39;&#39;` and `null` as `NaN`<br>    if (numValue &gt; max) {<br>        // ...<br>        return maxError(max, {message: getOption(config?.message, ctx)});<br>    }<br>    return undefined;<br>  });</pre><ol><li>A metadata installer, which stores values under a specific key (like MAX) using a function called aggregateMetadata.</li><li>The actual validation logic, defined in the validate function, which checks the condition and returns either an error or undefined.</li></ol><p>The [field] directive simply reads this metadata and passes it on to the host control — no magic, no reflection, no guessing. And that’s how the range input knew exactly what min and max to use..</p><h3>Final Thoughts</h3><p>The only real question left is this: can we define our own <em>custom</em> metadata keys — and have Angular pass them along to our controls just as effortlessly?</p><p>The short answer is <strong>absolutely yes</strong>.<br> But that’s a rabbit hole I’ll save for the next article.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=844f967ff6db" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Is Angular’s inject() Cheating? The Trick Behind Injection Context]]></title>
            <link>https://medium.com/@kobihari/is-angulars-inject-cheating-the-trick-behind-injection-context-51c2bf825461?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/51c2bf825461</guid>
            <category><![CDATA[context-injection]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[dependency-injection]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Sun, 16 Nov 2025 17:09:14 GMT</pubDate>
            <atom:updated>2025-11-16T17:09:14.568Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*HBCrigHD4YQwuP8eSYHzCg.png" /></figure><p>When Angular 14 introduced the inject function, it looked simple enough. A tiny helper that lets you grab a dependency without writing a constructor or a decorator. Nice and clean. But something about it didn’t sit quietly in my mind.</p><p>You see, Angular’s dependency‑injection system always works in relation to the “<strong><em>consumer</em></strong><em>” (</em>the thing asking for the service). One component might get one instance of Service A, while another gets something completely different, simply because each one starts from its own <strong>injector </strong>and walks upward through the hierarchy until it finds a provider.</p><p>And that leads to a pretty wild realization:</p><blockquote><em>For </em><em>inject to behave correctly, it has to know </em><strong><em>who is calling it</em></strong><em>.</em></blockquote><p>In over 25 years of writing JavaScript, I’ve had countless moments where I desperately wished I could write a function that asks, <em>“Hey, who just called me?”</em> And every single time, the answer was the same: <strong>you can’t</strong>. JavaScript simply doesn’t give you that power. No hidden API, no magical stack inspector, nothing.</p><p>So when I saw inject behaving as if it <em>did</em> know its caller… the question lingered:</p><p><strong>How the heck are they doing that?</strong></p><h3>How indeed…</h3><p>I remember sitting there, watching the Angular 14 keynote on YouTube, coffee in hand, when the thought hit me hard. If inject depends entirely on the <em>current injector</em>, then it must somehow know exactly which component or function is calling it.</p><p>And that didn’t make sense. Not in JavaScript. Not in anything I’d seen in 25 years.</p><p>So I stared at the screen and asked myself a question:</p><p><strong>Did the Angular team… cheat?</strong></p><p>Because if they didn’t, then they must’ve invented a trick the rest of us never had.</p><p>2 minutes after the keynote ended, I was searching through the Angular’s GitHub repository for the answer.</p><h3>Digging into the code</h3><p>First, I went straight to the inject function itself. Here’s the actual implementation:</p><pre>export function inject&lt;T&gt;(token: InjectionToken&lt;T&gt; | Constructor&lt;T&gt;): T {<br>  const currentInjector = getCurrentInjector();<br>  if (!currentInjector) {<br>    throw new Error(&#39;Current injector is not set.&#39;);<br>  }<br><br>  ///...<br><br>  return currentInjector.retrieve(token as InjectionToken&lt;T&gt;, options);<br>}</pre><p>Nothing fancy. It just grabs something called the <strong>current injector</strong>. But that immediately raised a question: <em>What exactly is this “current injector”?</em> Does it somehow magically depend on the caller?</p><p>So I kept digging.</p><pre>let _currentInjector: Injector | undefined | null = undefined;<br><br>export function getCurrentInjector(): Injector | undefined | null {<br>  return _currentInjector;<br>}</pre><p><em>Wait… what? </em><br><strong>A global variable?</strong><br>No call‑stack inspection. No sneaky runtime trick. Just a single global pointer sitting quietly in memory.</p><p>Which means one thing: before anyone can call inject, <strong>someone must set this variable</strong>. And sure enough, I found the function responsible:</p><pre>export function setCurrentInjector(<br>  injector: Injector | null | undefined,<br>): Injector | undefined | null {<br>  const former = _currentInjector;<br>  _currentInjector = injector;<br>  return former;<br>}</pre><p>This function is what makes everything possible. It swaps in a new injector, hands back the previous one, and lets its caller restore everything later.</p><p><strong>Finally, the last piece:</strong></p><pre>export function runInInjectionContext&lt;ReturnT&gt;(injector: Injector, fn: () =&gt; ReturnT): ReturnT {<br>  // ...<br>  const prevInjector = setCurrentInjector(injector);<br>  // ...<br>  try {<br>    return fn();<br>  } finally {<br>    setCurrentInjector(prevInjector);<br>  }<br>}</pre><p>This function temporarily switches the global injector, runs your callback, and then puts everything back exactly where it was.</p><p>So what Angular actually builds is a <strong>shadow stack: </strong>a parallel injector stack that lives alongside the real JavaScript call stack. Whenever inject runs, it simply looks at that global pointer and assumes, <em>&quot;Yep, that’s the injector of whoever called me.&quot;</em></p><p>It works. It’s clever. And yes… it’s a little bit dirty.</p><h3>Conclusion</h3><p>Now that I understood the implementation, the limitations suddenly felt less like a design choice and more like a direct consequence of the implementation itself.</p><p>inject isn’t a magic spell you can cast whenever you feel like it. It’s more like walking through a door that only exists for a brief moment, and only if someone else remembered to open it for you.</p><p>Angular opens that door automatically during component creation. It opens it again when the router runs resolvers, when guards execute, and in a few other well‑controlled moments. But outside those moments? The door simply isn’t there. Call inject from an event handler, or from a random callback, and Angular just stares back at you: <em>“Sorry… no injector.”</em></p><p>Angular calls that fleeting moment an <strong>Injection Context</strong> . This term refers to “the tiny slice of time where the global _currentInjector is pointing at the right place”.</p><p>And if <em>you</em> want to run a function that uses inject deep inside its logic, you have to create that moment yourself. In simple terms: you need to inject the right `Injector`, hold onto it, and then create a temporary &quot;injection context&quot; while the code runs.</p><p>Something like this:</p><pre>export class MyComponent {<br>  readonly myInjector = inject(Injector);<br><br>  onClick() {<br>       runInInjectionContenxt(this.myInjector, () =&gt; {<br>         // do something that relies on the `inject` function<br>       })<br>  }<br>}</pre><h3>The Bigger Picture</h3><p>It may feel like a dirty trick: a global variable, a shadow stack, a door that opens for only a split second. But this tiny mechanism became the cornerstone of the entire <strong><em>Angular renaissance</em></strong>. Modern Angular leans heavily on inject and the injection context, and <strong>signals rely on it completely</strong>. Without this trick, none of the new reactive primitives would work the way they do.</p><p>So yes, it’s a hack. But it’s also the quiet engine driving the most important shift Angular has made in years — and the reason signals now sit at the center of the modern Angular platform.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=51c2bf825461" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making a Read-Only Signal Editable in Your Component]]></title>
            <link>https://medium.com/@kobihari/making-a-read-only-signal-editable-in-your-component-22a5d8cbd22f?source=rss-5c9b8c556791------2</link>
            <guid isPermaLink="false">https://medium.com/p/22a5d8cbd22f</guid>
            <category><![CDATA[angular-signals]]></category>
            <category><![CDATA[linkedsignal]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Kobi Hari]]></dc:creator>
            <pubDate>Tue, 11 Nov 2025 19:13:04 GMT</pubDate>
            <atom:updated>2025-11-11T19:20:06.570Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*AEiiPOyOaaYG-rTVJWnEqA.png" /></figure><p>Sometimes you inject a signal from a service, and it’s <strong>read-only</strong>, but you still want the user to edit it inside your component.</p><pre>@Component({<br>  selector: &#39;user-editor&#39;,<br>  template: `<br>    &lt;input [(ngModel)]=&quot;?&quot;&gt;<br>  `<br>})<br>export class UserEditor {<br>    readonly user = inject(UserService).userSignal; // Signal&lt;User&gt;<br>    readonly username = computed(() =&gt; this.user().name); // Signal&lt;string&gt;<br><br>}</pre><p>How do you make that happen without breaking immutability?</p><blockquote>That’s where <em>linkedSignal()</em> comes in.</blockquote><h3>Linked Signal to the rescue</h3><p>Linked Signal creates a local writable signal that stays in sync with the original one, so you can use it for two-way binding with the familiar banana-in-a-box syntax <em>[(model)]</em>.</p><pre>@Component({<br>  selector: &#39;user-editor&#39;,<br>  template: `<br>    &lt;input [(ngModel)]=&quot;editableUsername&quot;&gt;<br>  `<br>})<br>export class UserEditor {<br>    readonly user = inject(UserService).userSignal; // Signal&lt;User&gt;<br>    readonly username = computed(() =&gt; this.user().name); // Signal&lt;string&gt;<br>    readonly editableUsername = linkedSignal(() =&gt; this.username());<br>}</pre><p>- Keeps your parent state immutable<br>- Allows local edits in the child<br>- Feels natural for Angular developers</p><p>That’s the beauty of <em>linkedSignal</em>. It bridges Angular’s modern signal world with the old-school simplicity of banana-in-a-box syntax.</p><h3>Value Source</h3><p>Now the linked signal may hold a value that’s either coming from the service or modified locally by the user.<br>But how do you tell which one it is?</p><p>You can use a computed signal to compare the original value with the current value of the linked signal:</p><pre>readonly valueSource = computed(() =&gt; <br> this.username() === this.editableUsername()<br> ? &#39;remote&#39;<br> : &#39;local&#39;);</pre><p>The <em>valueSource </em>signal now tells you whether the current value is local (changed by the user) or remote (still matches the service).</p><p><em>If you found this useful, follow me for more posts about Angular Signals, NgRx Signal Store, and building scalable Angular apps.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22a5d8cbd22f" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>