{"id":7179,"date":"2023-05-20T00:43:58","date_gmt":"2023-05-19T22:43:58","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=7179"},"modified":"2023-05-20T00:43:58","modified_gmt":"2023-05-19T22:43:58","slug":"angular-signals-your-architecture-5-options","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/","title":{"rendered":"Angular Signals &#038; Your Architecture: 5 Options"},"content":{"rendered":"<p>Signals are one of the most exciting features that have appeared in the Angular space recently. But how do they influence your architecture? This article provides 5 different options and some technical background information you should consider.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/standalone-example-cli\">Source Code<\/a><br \/>\n(\ud83d\udd00 <strong>Branches:<\/strong> <code>arc-*<\/code>)<\/p>\n<h2>Option 1: Signals in Component<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-simple<\/code><\/p>\n<p>A straightforward approach is to use Signals in your components directly. Each property you want to data bind becomes a Signal:<\/p>\n<pre><code class=\"language-typescript\">@Component({ ... })\nexport class FlightSearchComponent  {\n\n  private flightService = inject(FlightService);\n\n  from = signal(&#039;Hamburg&#039;);\n  to = signal(&#039;Graz&#039;);\n  flights = signal&lt;Flight[]&gt;([]);\n\n  async search() {\n    if (!this.from() || !this.to()) return;\n\n    const flights = await this.flightService.findPromise(this.from(), this.to());\n    this.flights.set(flights);\n  }\n\n  [...]\n\n}<\/code><\/pre>\n<p>Then, you can directly bind these signals in the template:<\/p>\n<pre><code class=\"language-html\">&lt;input [ngModel]=&quot;from()&quot; (ngModelChange)=&quot;from.set($event)&quot; name=&quot;from&quot; \/&gt;\n\n&lt;input [ngModel]=&quot;to()&quot; (ngModelChange)=&quot;to.set($event)&quot; name=&quot;to&quot; \/&gt;\n\n&lt;button (click)=&quot;search()&quot;&gt;Search&lt;\/button&gt;\n\n&lt;div class=&quot;row&quot;&gt;\n  &lt;div *ngFor=&quot;let f of flights()&quot;&gt;\n    &lt;app-flight-card [item]=&quot;f&quot; \/&gt;\n  &lt;\/div&gt;\n&lt;\/div&gt;<\/code><\/pre>\n<p>As of writing this, <code>ngModel<\/code> and other parts of the <code>FormModule<\/code> don't support two-way bindings for Signals. The Angular team will take care of a revision of forms support soon. For this reason, the previous example implements two-way binding manually by explicitly setting up a property binding for <code>ngModel<\/code> and an event binding for <code>ngModelChange<\/code>.<\/p>\n<p>In a traditional component, binding a Signal in a template is similar to binding an Observable with the <code>async<\/code> pipe. Hence, we can also turn on <code>OnPush<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/\/ Let&#039;s switch on OnPush for\n\/\/ FlightCardComponent and FlightSearchComponent\n@Component({\n    [...]\n    changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class [...]  {\n    [...]\n}<\/code><\/pre>\n<p>Angular checks <code>OnPush<\/code> components when the <code>async<\/code> pipe provides a new value. Since Angular 16, the same is the case when a bound Signal is updated. Assigning a new value to the <code>flights<\/code> Signal makes Angular update the <code>FlightSearchComponent<\/code>.<\/p>\n<p>However, this is only one side of the coin: Angular also has to find out which child components need to be updated. It checks the values bound to the child components' properties. Only the object reference is checked when binding complex data types like objects or arrays. This is why Observables are usually used together with immutable data structures (Immutables). Instead of mutating such objects, a new object with the changed values is created.<\/p>\n<p>If we just wanted to delay the first flight, the source code would look like as follows:<\/p>\n<pre><code class=\"language-typescript\">delay(): void {\n  const flights = this.flights();\n  const flight = flights[0];\n\n  const date = addMinutes(flight.date, 15);\n\n  this.flights.update(flights =&gt; ([\n    { ...flight, date },\n    ...flights.slice(1)\n  ]));\n}<\/code><\/pre>\n<p>The following code would not work when using <code>OnPush<\/code> as it is not changing the object reference of the respective flight:<\/p>\n<pre><code class=\"language-typescript\">\/\/ Alternative w\/ Mutables:\n\/\/ Won&#039;t work with OnPush\nthis.flights.mutate((flights) =&gt; {\n  flights[0].date = date;\n});<\/code><\/pre>\n<p>Instead of using Signals with Immutables, one could also use nested Signals, e. g. a Signal with an Array containing Signals with flights. However, such structures needed to be created by hand; hence I assume that sticking with Immutables is easier for now. The following section explains that switching to nested Signals can speed up the data binding once we get the envisioned Signal Components.<\/p>\n<h2>Excursus: Change Detection in Angular -- Today and Tomorrow<\/h2>\n<p>When not using <code>OnPush<\/code>, Angular checks all components for updates after event handlers ran. Components in <code>OnPush<\/code> mode, however, are only checked if they have been marked as dirty. This happens, for instance, if an Observable bound with <code>async<\/code> or a bound Signal emits a new value. <\/p>\n<p>When (the object reference of) a bound input changes, the component is marked too. Together with the component, all ancestors in the component tree are marked, as Angular's change detection traverses the component tree top\/down. Interestingly, marked components are always fully checked for changes, even if only an update affects a part. <\/p>\n<p>Signal Components, envisioned for future Angular versions, will provide a more fine-grained behavior: Only changed parts of components will be checked. These parts will be embedded views defined by structural directives like <code><em>ngFor<\/code> or <code><\/em>ngIf<\/code>. Also, ancestors of Signal Components won't automatically be checked.<\/p>\n<p>In this case, having nested signals will provide an advantage over Immutables, as they allow our application to directly notify Angular about the component parts that need to be updated. <\/p>\n<h2>Option 2: Move Signals to a Service<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-facade2<\/code><\/p>\n<p>Signals are not limited to be used in components. By design, they can be used everywhere. Hence, we can also move them into a service:<\/p>\n<pre><code class=\"language-typescript\">@Injectable({ providedIn: &#039;root&#039; })\nexport class FlightBookingFacade {\n  private flightService = inject(FlightService);\n\n  readonly flights = signal&lt;Flight[]&gt;([]);\n  readonly from = signal(&#039;Hamburg&#039;);\n  readonly to = signal(&#039;Graz&#039;);\n\n  async load(): Promise&lt;void&gt; {\n    [...]\n  }\n\n  delay(): void {\n    [...]\n  }\n}<\/code><\/pre>\n<p>Such services can be used by several components and hence allow for sharing state. But even if only used by one component, they provide some added value: One can relieve the component from taking care of state management, and the service can preserve the state when the component is destroyed and re-created, e.g., when leaving a route and returning to it.<\/p>\n<p>The component can use such a service as follows:<\/p>\n<pre><code class=\"language-typescript\">@Component({ ... })\nexport class FlightSearchComponent  {\n\n  private facade = inject(FlightBookingFacade);\n\n  from = this.facade.from;\n  to = this.facade.to;\n  flights = this.facade.flights;\n\n  async search() {\n    this.facade.load();\n  }\n\n  delay(): void {\n    this.facade.delay();\n  }\n\n}<\/code><\/pre>\n<h2>Option 3: Information Hiding With Services<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-facade3<\/code><\/p>\n<p>If several components use a service, it might be a good idea to make the exposed Signals read\/only. This forces all the components to update the state in a well-defined way, e.g., by calling service methods intended for the update in question.<\/p>\n<p>For creating a read\/only Signal out of a writable one, the method <code>asReadonly<\/code> can be used:<\/p>\n<pre><code class=\"language-typescript\">@Injectable({ providedIn: &#039;root&#039; })\nexport class FlightBookingFacade {\n  private flightService = inject(FlightService);\n\n  private _flights = signal&lt;Flight[]&gt;([]);\n  readonly flights = this._flights.asReadonly();\n\n  private _from = signal(&#039;Hamburg&#039;);\n  readonly from = this._from.asReadonly();\n\n  private _to = signal(&#039;Graz&#039;);\n  readonly to = this._to.asReadonly();\n\n  updateCriteria(from: string, to: string): void {\n    this._from.set(from);\n    this._to.set(to);\n  }\n\n  [...]\n}<\/code><\/pre>\n<p>This style is also known from RxJS where writable <code>Subjects<\/code> are converted to read\/only <code>Observables<\/code>. Unfortunately, this code is quite lengthy. The following section provides a solution.<\/p>\n<h2>Option 3a: Service with State-Signal<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-facade3a<\/code><\/p>\n<p>To streamline option 3 a bit, we could introduce a private writable <code>state<\/code> Signal and derive the individual read\/only Signals from it via <code>computed<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { equal, patchSignal } from &#039;..\/..\/..\/shared\/util-common&#039;;\n\n[...]\n\n@Injectable({ providedIn: &#039;root&#039; })\nexport class FlightBookingFacade {\n  private flightService = inject(FlightService);\n\n  private state = signal({\n    from: &#039;Hamburg&#039;,\n    to: &#039;Graz&#039;,\n    flights: [] as Flight[],\n    basket: {} as Record&lt;number, boolean&gt;,\n  });\n\n  readonly flights = computed(() =&gt; this.state().flights, { equal });\n  readonly from = computed(() =&gt; this.state().from, { equal });\n  readonly to = computed(() =&gt; this.state().to, { equal });\n  readonly basket = computed(() =&gt; this.state().basket, { equal });\n\n  updateCriteria(from: string, to: string): void {\n    patchSignal(this.state, { from, to });\n  }\n\n  [...]\n\n}<\/code><\/pre>\n<p>This already looks like the usage of a lightweight store like the NGRX Component Store. The used helper function <code>patchState<\/code> does indeed borrow one of the Component Store's ideas:<\/p>\n<pre><code class=\"language-typescript\">export function patchSignal&lt;T&gt;(signal: WritableSignal&lt;T&gt;, partialState: Partial&lt;T&gt;) {\n  signal.update((state) =&gt; ({\n    ...state,\n    ...partialState,\n  }));\n}<\/code><\/pre>\n<p>Of course, store libraries provide additional features, and as of writing this, an NGRX Signal Store is in the works. I'm going to update this article once the signal store is available.<\/p>\n<p>The helper function <code>equal<\/code> tells the Signal, when its value is considered to be changed. As we are going with Immutable state, it's just about comparing object references and primitive values. For both, the <code>===<\/code> operator is used:<\/p>\n<pre><code class=\"language-typescript\">export function equal&lt;T&gt;(a: T, b: T): boolean {\n    return a === b;\n}<\/code><\/pre>\n<h2>Excursus: The equal Function<\/h2>\n<p>Each Signal has an <code>equal<\/code> function defining when its value is considered to be changed. This function is called after updating the Signal. Only if it returns <code>false<\/code>, the consumers are notified. At least this is how it can be seen on the logical level. On the implementation level it's a bit more complicated.<\/p>\n<p>Consumers are computed Signals and effects. Angular's change detection also uses the latter to track the bound Signals values.<\/p>\n<p>The default implementation we get when not explicitly setting this function works as follows:<\/p>\n<ul>\n<li>For objects (including arrays), <code>false<\/code> is always returned.<\/li>\n<li>Otherwise (e. g. for strings, numbers, booleans), the result of <code>oldValue === newValue<\/code> is returned.<\/li>\n<\/ul>\n<p>The first bullet point might be surprising. The reason is that the Signal cannot know how to compare our complex structures, and always performing a deep comparison seems too costly. Just returning <code>false<\/code> makes it work with mutable data too. Obviously, this also leads to more notifications as actually needed. The comparison described in the second bullet point ensures that consumers are not notified if a signal is updated with the same primitive value.<\/p>\n<p>As we use immutable state in the examples shown here, our custom <code>equal<\/code> function can always compare the former value with the current value.<\/p>\n<p>Unfortunately, there is a small caveat when using Immutables: When a part of the immutable state is changed, the whole state object must also be changed. You can see this in the discussed <code>patchSignal<\/code> function: It always returns a new state object, the former state, but also the new partial state is spread into. Consequently, all <code>computed<\/code> Signals are recomputed. As our computations are just projections (e. g. from <code>state<\/code> to <code>state().flights<\/code>), this shouldn't be too costly. <\/p>\n<p>However, it would be costly if Angular marked the components as dirty after each re-computation. The registered <code>equal<\/code> function prevents this: It returns <code>true<\/code> if the object reference did not change. As a result, the Signal does not notify Angular, and the component is not marked as dirty.<\/p>\n<p>As of writing this, it seems like all the existing store implementations adapted for Signals recently have this behavior. This isn't that surprising because they internally use immutable data structures. According to a first RFC document, the envisioned NGRX Signal Store will internally have separate Signals for each top-level state property. This reduces the issue at hand. <\/p>\n<h2>Option 3b: Adding a Simple Store<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-facade3d<\/code><\/p>\n<p>While the previous option was easy to read and maintain, it has two drawbacks: One has to remember to use an equal function for immutables, and there is just one signal for the whole state. Ideally, a Signal just contains elements that usually change together. A simple generic solution would at least create one Signal for each property on root level. Both can be automated with a simple hand-made store:<\/p>\n<pre><code class=\"language-typescript\">@Injectable({ providedIn: &#039;root&#039; })\nexport class FlightBookingFacade {\n  private flightService = inject(FlightService);\n\n  private state = createStore({\n    from: &#039;Hamburg&#039;,\n    to: &#039;Graz&#039;,\n    flights: [] as Flight[],\n    basket: {} as Record&lt;number, boolean&gt;,\n  });\n\n  \/\/ Option 1: fetch root signals as readonly\n  flights = this.state.select(s =&gt; s.flights());\n  from = this.state.select(s =&gt; s.from());\n  to = this.state.select(s =&gt; s.to())\n  basket = this.state.select(s =&gt; s.basket());\n\n  \/\/ Option 2: use selectors for computing a view model\n  selected = this.state.select(s =&gt; s.flights().filter(f =&gt; s.basket()[f.id]));\n\n  updateCriteria(from: string, to: string): void {\n    this.state.update(&#039;from&#039;, from);\n    this.state.update(&#039;to&#039;, to);\n  }\n\n  [...]\n}<\/code><\/pre>\n<p>Internally, the store maintains a separate signal for each property at root level, and the <code>select<\/code>`` method is just a wrapper around computed that passes a respective equal function.<\/p>\n<p>The <a href=\"https:\/\/github.com\/manfredsteyer\/standalone-example-cli\/blob\/arc-facade3d\/src\/app\/shared\/util-common\/signal-utils.ts\">store<\/a> itself can be written with about 60 lines of code. Please find it <a href=\"https:\/\/github.com\/manfredsteyer\/standalone-example-cli\/blob\/arc-facade3d\/src\/app\/shared\/util-common\/signal-utils.ts\">here<\/a>.<\/p>\n<h2>Option 4: Using a Store and the Redux Pattern<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-ngrx<\/code><\/p>\n<p>We could also use a store library as an alternative to manage the state in a service by hand. Choosing one that follows the Redux pattern ensures the state is only modified in a well-defined way. The most popular Redux implementation for Angular is NGRX. Fortunately, it has been supporting Signals since version 16.<\/p>\n<p>The following example shows how its new <code>selectSignal<\/code> method allows retrieving a part of the immutable state tree as a <code>Signal<\/code>:<\/p>\n<pre><code class=\"language-TypeScript\">@Component({ ... })\nexport class FlightSearchComponent {\n  private store = inject(Store);\n\n  criteria = this.store.selectSignal(ticketingFeature.selectCriteria);\n  flights = this.store.selectSignal(ticketingFeature.selectFlights);\n\n  updateCriteria(from: string, to: string): void {\n    this.store.dispatch(ticketingActions.updateCriteria({ from, to }));\n  }\n\n  search(): void {\n    this.store.dispatch(\n      ticketingActions.loadFlights({\n        from: this.criteria().from,\n        to: this.criteria().to,\n      })\n    );\n  }\n\n  delay(): void {\n    const flights = this.flights();\n    const id = flights[0].id;\n    this.store.dispatch(ticketingActions.delayFlight({ id }));\n  }\n\n}<\/code><\/pre>\n<p>The complete usage of NGRX, including the source code defining the state, actions, reducers, and effects, can be found in the \ud83d\udd00 branch <code>arc-ngrx<\/code>.<\/p>\n<h2>Option 5: Hiding the Store Behind a Facade<\/h2>\n<p>\ud83d\udd00 Branch: <code>arc-ngrx-facade<\/code><\/p>\n<p>Sometimes, hiding the used store implementation behind a service can be beneficial. Such a so-called facade provides a domain-specific interface and allows to introduce the store gradually or to use it selectively:<\/p>\n<pre><code class=\"language-typescript\">@Injectable({ providedIn: &#039;root&#039; })\nexport class FlightBookingFacade {\n  private store = inject(Store);\n\n  criteria = this.store.selectSignal(ticketingFeature.selectCriteria);\n  flights = this.store.selectSignal(ticketingFeature.selectFlights);\n\n  updateCriteria(from: string, to: string): void {\n    this.store.dispatch(ticketingActions.updateCriteria({ from, to }));\n  }\n\n  load(): void {\n    if (!this.criteria().from || !this.criteria().to) return;\n    this.store.dispatch(\n      ticketingActions.loadFlights({\n        from: this.criteria().from,\n        to: this.criteria().to,\n      })\n    );\n  }\n\n  delay(): void {\n    const flights = this.flights();\n    const id = flights[0].id;\n    this.store.dispatch(ticketingActions.delayFlight({ id }));\n  }\n}<\/code><\/pre>\n<p>If you know from the beginning that you will go all-in with your store, wrapping it in such a facade might be overhead.<\/p>\n<h2>Conclusion<\/h2>\n<p>Signals can be defined directly within components but also within a service. In the latter case, public read\/only Signals can be derived from a private writable Signal. By providing methods for manipulating the state, one can ensure that the state is only modified in a well-defined way. Instead of hand-writing such a service, existing store libraries adapted for Signals can be used. A famous example is NGRX.<\/p>\n<p>Also, it will be interesting to see how store libraries will evolve to better support Signals and the upcoming Signal Components. A promising development is the envisioned NGRX Signal Store.<\/p>\n<h2>What's next? More on Architecture!<\/h2>\n<p>Please find more information on enterprise-scale Angular architectures in our free eBook (5th edition, 12 chapters): <\/p>\n<ul>\n<li>According to which criteria can we subdivide a huge application into sub-domains?<\/li>\n<li>How can we make sure, the solution is maintainable for years or even decades?<\/li>\n<li>Which options from Micro Frontends are provided by Module Federation?<\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.angulararchitects.io\/book\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2022\/12\/cover-5th-small.png\" alt=\"free ebook\"><\/a><\/p>\n<p>Feel free to <a href=\"https:\/\/www.angulararchitects.io\/en\/book\">download it here<\/a> now!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article provides 5 different options and some technical background information for building architectures with Signals.<\/p>\n","protected":false},"author":9,"featured_media":7184,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7179","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-unkategorisiert"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular Signals &amp; Your Architecture: 5 Options - ANGULARarchitects<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular Signals &amp; Your Architecture: 5 Options - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"This article provides 5 different options and some technical background information for building architectures with Signals.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2023-05-19T22:43:58+00:00\" \/>\n<meta name=\"author\" content=\"Manfred Steyer, GDE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@daniel\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer, GDE\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Angular Signals &#038; Your Architecture: 5 Options\",\"datePublished\":\"2023-05-19T22:43:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\"},\"wordCount\":1702,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg\",\"articleSection\":[\"Unkategorisiert\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\",\"name\":\"Angular Signals & Your Architecture: 5 Options - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg\",\"datePublished\":\"2023-05-19T22:43:58+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg\",\"width\":1000,\"height\":667},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Angular Signals &#038; Your Architecture: 5 Options\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\",\"name\":\"Manfred Steyer, GDE\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer, GDE\"},\"sameAs\":[\"https:\/\/x.com\/daniel\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular Signals & Your Architecture: 5 Options - ANGULARarchitects","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/","og_locale":"en_US","og_type":"article","og_title":"Angular Signals & Your Architecture: 5 Options - ANGULARarchitects","og_description":"This article provides 5 different options and some technical background information for building architectures with Signals.","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/","og_site_name":"ANGULARarchitects","article_published_time":"2023-05-19T22:43:58+00:00","author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Angular Signals &#038; Your Architecture: 5 Options","datePublished":"2023-05-19T22:43:58+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/"},"wordCount":1702,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg","articleSection":["Unkategorisiert"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/","name":"Angular Signals & Your Architecture: 5 Options - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg","datePublished":"2023-05-19T22:43:58+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/05\/shutterstock-138040406.jpg","width":1000,"height":667},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals-your-architecture-5-options\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Angular Signals &#038; Your Architecture: 5 Options"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951","name":"Manfred Steyer, GDE","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a0b59539674d8b71ea1c1f4764b11244b5f499203f1d11b40f37d8f3f90be033?s=96&d=mm&r=g","caption":"Manfred Steyer, GDE"},"sameAs":["https:\/\/x.com\/daniel"]}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/7179","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=7179"}],"version-history":[{"count":0,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/7179\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/7184"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=7179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=7179"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=7179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}