{"id":27933,"date":"2025-01-26T23:24:19","date_gmt":"2025-01-26T22:24:19","guid":{"rendered":"https:\/\/www.angulararchitects.io\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/"},"modified":"2025-06-03T16:38:20","modified_gmt":"2025-06-03T14:38:20","slug":"streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/","title":{"rendered":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World"},"content":{"rendered":"<div class=\"wp-post-series-box series-signals wp-post-series-box--expandable\">\n\t\t\t<input id=\"collapsible-series-signals6ab0663e2cb0f\" class=\"wp-post-series-box__toggle_checkbox\" type=\"checkbox\">\n\t\n\t<label\n\t\tclass=\"wp-post-series-box__label\"\n\t\t\t\t\tfor=\"collapsible-series-signals6ab0663e2cb0f\"\n\t\t\ttabindex=\"0\"\n\t\t\t\t>\n\t\t<p class=\"wp-post-series-box__name wp-post-series-name\">\n\t\t\tThis is post 8 of 9 in the series <em>&ldquo;Signals&rdquo;<\/em>\t\t<\/p>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"wp-post-series-box__posts\">\n\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/angular-signals\/\">Signals in Angular: Building Blocks<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/component-communication-with-signals-inputs-two-way-bindings-and-content-view-queries\/\">Component Communication with Signals: Inputs, Two-Way Bindings, and Content\/ View Queries<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/successful-with-signals-in-angular-3-effective-rules-for-your-architecture\/\">Successful with Signals in Angular &#8211; 3 Effective Rules for Your Architecture<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/skillfully-using-signals-in-angular-selected-hints-for-professional-use\/\">Skillfully Using Signals in Angular &#8211; Selected Hints for Professional Use<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/when-not-to-use-effects-in-angular-and-what-to-do-instead\/\">When (Not) to use Effects in Angular &#8212; and what to do instead<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/asynchronous-resources-with-angulars-new-resource-api\/\">Asynchronous Data Flow with Angular&#8217;s new Resource API<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-in-angular-19-2-details-and-semantics\/\">Streaming Resources in Angular &#8211; Details and Semantics<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World<\/span><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/learning-httpresource-with-super-mario\/\">Angular&#8217;s new httpResource<\/a><\/li>\n\t\t\t\t\t\t\t<\/ol>\n\t\t<\/div>\n\t<\/div>\n<p>The minimal example in the privous article was already comprehensive enough to discuss the use of Streaming Resources and their semantic details. With this article, I would like to go a step further and show a more practical use case. This is a simple chat client, allowing further details to be discussed.<\/p>\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/chat.png\" alt=\"A simple chat based on a streaming resource\" \/><\/p>\n<p>Technically speaking, this chat example differs from the Timer in one crucial aspect: all messages received are relevant, not just the last one. This presents a small challenge in the signal-based world but can be solved.<\/p>\n<p>A fork of a sample project from the <a href=\"https:\/\/github.com\/mdn\/samples-server.git\">Mozilla Developer Network<\/a> is used as the chat server. This Node-based server is included in the <a href=\"https:\/\/github.com\/manfredsteyer\/desserts.git\">sample project<\/a> and its <em>readme.md<\/em> shows how to start it.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/manfredsteyer\/desserts.git\">Source Code<\/a><\/p>\n<blockquote><p>\nBig thanks to <a href=\"https:\/\/bsky.app\/profile\/synalx.bsky.social\">Alex Rickabaugh<\/a> from the Angular team for reviewing the examples and for the insightful discussions about the proper usage of Streaming Resources for messaging.\n<\/p><\/blockquote>\n<p>This article has been updated for the changes introduced to the -- back then -- experimental API with Angular 20. In Angular 19, there are some minor differences.<\/p>\n<h2>Consumer's Perspective<\/h2>\n<p>In our example, the Angular client initializes the chat with the <em>chatConnection<\/em> factory. It provides a structure representing the individual chat messages as a streaming resource and offers additional Signals and a <em>send<\/em> method:<\/p>\n<pre><code class=\"language-ts\">@Component([\u2026])\nexport class ChatResourceComponent {\n  ResourceStatus = ResourceStatus;\n\n  userName = signal(&#039;&#039;);\n  chat = chatConnection(&#039;ws:\/\/localhost:6502&#039;, this.userName);\n  messages = computed(() =&gt; this.chat.resource.value() ?? []);\n\n  userNameInField = linkedSignal(() =&gt; this.chat.acceptedUserName());\n  currentMessage = signal&lt;string&gt;(&#039;&#039;);\n\n  send() {\n    this.chat.send(this.currentMessage());\n    this.currentMessage.set(&#039;&#039;);\n  }\n\n  join() {\n    this.userName.set(this.userNameInField());\n  }\n}<\/code><\/pre>\n<p>The <em>userName<\/em> Signal passed to <em>chatConnection<\/em> triggers the Resource and establishes a connection with the chat server. The <em>userNameInField<\/em> and <em>currentMessages<\/em> Signals are bound to input fields. To establish a connection, the <em>join<\/em> function writes the value of <em>userNameInField<\/em> to the <em>userName Signal<\/em>.<\/p>\n<p>The server can correct the requested username to ensure uniqueness. Therefore, <em>userNameInField<\/em> is implemented with <em>linkedSignal<\/em>. This Linked Signal overwrites the local value with the corrected value from the server, which is contained in the <em>accpetedUserName<\/em> Signal.<\/p>\n<p>When the user wants to send a message, the application passes the <em>currentMessage<\/em> to the <em>send<\/em> method. It then resets the <em>currentMessage<\/em> so that the user can enter the next message.<\/p>\n<h2>Glitch-Free Property as Challenge at Streaming Resources<\/h2>\n<p>The chat example differs from the timer discussed in the previous article in one essential aspect: while the timer was only interested in the latest message from the stream, the chat is interested in all messages received so far, or at least all messages from a defined time window. In other words, the timer represents an object that changes over time. In contrast, the chat represents several events with messages the application has to take into account in their entirety.<\/p>\n<p>The way we look at the timer here fits well with signals, especially since signals always reflect the most recent value. The glitch-free property, which ignores unnecessary intermediate values, also fits here: If the Resource were to change the timer from 0 to 1, from 1 to 2, and from 2 to 3 in one single task, the resource consumer would only see the value 3.<\/p>\n<p>However, this behavior would be fatal in an event-based use, such as chat. Here, individual messages would be lost. This behavior can easily be tested by having the chat server send the same message several times in a row to the same client. Most of these repetitions would be lost in an implementation that only considers the last message received.<\/p>\n<p>This consideration shows that, unlike Observables in RxJS, Signals are not well suited to representing events or messages! This presents us with a challenge when using streaming resources, which fortunately can be overcome by simply adjusting our perspective: If we let the Resource represent not only the current value but all messages received so far, or at least all messages in a time window that is of interest to us, we can again view this totality of messages as a value that changes over time.<\/p>\n<p>In other words, we need to move the collection and management of individual messages to the Resource. This view also fits well with the observation in the previous article that in the Signals world, use case-specific and, thus, coarse-grained building blocks are used.<\/p>\n<h2>More on this: Angular Architecture Workshop (Remote, Interactive, Advanced)<\/h2>\n<p>Become an expert for enterprise-scale and maintainable Angular applications with our <a href=\"https:\/\/www.angulararchitects.io\/en\/angular-workshops\/advanced-angular-enterprise-architecture-incl-ivy\/\">Angular Architecture workshop!<\/a><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/sujet-en.jpg\" alt=\"\" \/><\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/en\/angular-workshops\/advanced-angular-enterprise-architecture-incl-ivy\/\">English Version<\/a> | <a href=\"https:\/\/www.angulararchitects.io\/schulungen\/advanced-angular-enterprise-anwendungen-und-architektur\/\">German Version<\/a><\/p>\n<h2>Messages and Protocol<\/h2>\n<p>The example defines several types for the individual messages that the client exchanges with the chat server:<\/p>\n<pre><code class=\"language-ts\">export type ChatRequest =\n  | {\n      type: &#039;username&#039;;\n      id: number;\n      name: string;\n    }\n  | {\n      type: &#039;message&#039;;\n      id: number;\n      text: string;\n    };\n\nexport type ChatResponse =\n  | {\n      type: &#039;id&#039;;\n      id: number;\n    }\n  | {\n      type: &#039;username&#039;;\n      id: number;\n      name: string;\n    }\n  | {\n      type: &#039;message&#039;;\n      id: number;\n      name: string;\n      text: string;\n    };<\/code><\/pre>\n<p>The protocol between the client and server is as follows:<\/p>\n<ol>\n<li>The client establishes a web socket connection.<\/li>\n<li>The server responds with a <em>ChatResponse<\/em> of type <em>id<\/em>, via which the client receives a unique session id.<\/li>\n<li>The client sends a <em>ChatRequest<\/em> of type <em>username<\/em> to inform the user's name.<\/li>\n<li>The server confirms this username with a <em>ChatResponse<\/em> of type <em>username<\/em>. If the desired username is already taken, the client receives a corrected username via this message, which the server creates by appending a number to the preferred one.<\/li>\n<li>The client sends <em>ChatRequests<\/em> with its messages (type <em>message)<\/em>. The server distributes this message to all clients as a <em>ChatResponse<\/em> of type <em>message.<\/em><\/li>\n<\/ol>\n<h2>Representation of the Chat<\/h2>\n<p>The connection to the chat is represented by the example with the type <em>ChatConnection<\/em>:<\/p>\n<pre><code class=\"language-ts\">export type SendFn = (message: string) =&gt; void;\n\nexport type ChatConnection = {\n  resource: ResourceRef&lt;ChatResponse[] | undefined&gt;;\n  connected: () =&gt; boolean;\n  acceptedUserName: () =&gt; string;\n  send: SendFn;\n};<\/code><\/pre>\n<p>The heart of the <em>ChatConnection<\/em> is a Resource that represents all messages received so far in the form of an array. It also provides further status information as signals. This includes the connection status (<em>connected<\/em>) and the username (<em>acceptedUserName<\/em>) corrected by the server if necessary.<\/p>\n<p>The <em>send<\/em> method allows the chat to send messages to the server. The implementation maps the passed string to a <em>ChatRequest<\/em> of type <em>message<\/em>.<\/p>\n<h2>Factory for the Chat<\/h2>\n<p>The factory for the chat is structured similarly to the one for the timer discussed previously. However, it initially prepares a few additional variables:<\/p>\n<pre><code class=\"language-ts\">export function chatConnection(\n  websocketUrl: string,\n  userName: () =&gt; string\n): ChatConnection {\n\n  let connection: WebSocket;\n\n  const connected = signal(false);\n  const id = signal(0);\n  const acceptedUserName = signal(&#039;&#039;);\n\n  const params = computed(() =&gt; ({\n    userName: userName(),\n  }));\n\n  const chatResource = resource({\n    params,\n    stream: async (loaderParams) =&gt; {\n      \/\/ init web socket connection\n      \/\/ handle and collect messages\n      [\u2026]\n    },\n  });\n\n  const send: SendFn = (message: string) =&gt; {\n    const request: ChatRequest = {\n      type: &#039;message&#039;,\n      id: id(),\n      text: message,\n    };\n    connection.send(JSON.stringify(request));\n  };\n\n  return {\n    connected,\n    resource: chatResource,\n    acceptedUserName,\n    send,\n  };\n}<\/code><\/pre>\n<p>These variables include the <em>connection<\/em>, which reflects the web socket connection established by the Streaming Loader, the previously mentioned <em>connected<\/em> and <em>accpetedUserName<\/em> Signals, and an <em>id<\/em> Signal representing the current user session. In the end, the factory returns a few of these Signals, the created Streaming Resource, and the <em>send<\/em> method as a <em>ChatConnection<\/em>. It does not publish the <em>id<\/em> Signal, as this is an implementation detail.<\/p>\n<p>The streaming loader of the resource first creates an Array <em>messages<\/em> in which it collects the received chat messages:<\/p>\n<pre><code class=\"language-ts\">const chatResource = resource({\n  request,\n  stream: async (loaderParams) =&gt; {\n    const userName = loaderParams.params.userName;\n\n    let messages: ChatResponse[] = [];\n\n    \/\/ 1. Create Signal representing the Stream\n    const resultSignal = signal&lt;ResourceStreamItem&lt;ChatResponse&gt;&gt;({\n      value: messages,\n    });\n\n    if (!userName) {\n      return resultSignal;\n    }\n\n    \/\/ 2. Set up async logic updating the Signal\n    connection = new WebSocket(websocketUrl, &#039;json&#039;);\n\n    connection.addEventListener(&#039;open&#039;, (event) =&gt; {\n      console.log(&#039;[open]&#039;);\n      connected.set(true);\n    });\n\n    connection.addEventListener(&#039;message&#039;, (event) =&gt; {\n      const value = JSON.parse(event.data) as ChatResponse;\n      console.log(&#039;[message]&#039;, value);\n\n      if (value.type === &#039;id&#039;) {\n        id.set(value.id);\n        sendUserName(value.id, userName, connection);\n      }\n\n      if (value.type === &#039;username&#039; &amp;&amp; value.id == id()) {\n        acceptedUserName.set(value.name);\n      }\n\n      if (value.type === &#039;message&#039; || value.type === &#039;username&#039;) {\n        messages = [...messages, value];\n        resultSignal.set({ value: messages });\n      }\n    });\n\n    connection.addEventListener(&#039;error&#039;, (event) =&gt; {\n      const error = new Error(<code>Error with websocket connection<\/code>);\n      console.log(&#039;[event]&#039;, event);\n      resultSignal.set({ error });\n    });\n\n    \/\/ 3. Set up clean-up handler triggered by AbortSignal\n    params.abortSignal.addEventListener(&#039;abort&#039;, () =&gt; {\n      console.log(&#039;clean up!&#039;);\n      connection.close();\n      connected.set(false);\n      id.set(0);\n      acceptedUserName.set(&#039;&#039;);\n    });\n\n    \/\/ 4. Return Signal\n    return resultSignal;\n  },\n});\n\nfunction sendUserName(id: number, userName: string, connection: WebSocket) {\n  const message: ChatRequest = {\n    type: &#039;username&#039;,\n    id: id,\n    name: userName,\n  };\n  connection.send(JSON.stringify(message));\n}<\/code><\/pre>\n<p>The rest of the implementation follows the four points discussed in the previous article. The prepared signal reflects the stream and contains the managed Array with the received messages.<\/p>\n<p>The client receives information from the server via the configured event handlers. The <em>message<\/em> event takes care of the protocol described above. It adds all received messages to the messages Array. This must be done immutably, i.e., using a shallow copy, so the Signal perceives the change.<\/p>\n<p>The <em>open<\/em> event sets <em>connected<\/em> to <em>true,<\/em> and the <em>error<\/em> event writes the current error to the stream. The <em>AbortSignal\u2019s abort<\/em> event closes the web socket connection and resets the managed properties. At the end, the Streaming Loader returns the signal reflecting the stream as usual.<\/p>\n<h2>Conclusion<\/h2>\n<p>Signals in Angular always only represent the current value. Intermediate values for changes that follow one another in the same task are ignored (Glitch Free property). This is well suited for changing states, such as a counter, but can lead to data loss in event flows - such as a chat that should display all received messages. <\/p>\n<p>The solution is to collect the messages received (in the time window of interest) in the Resource and publish the resulting array via the resource. This array, therefore, corresponds to a value that changes over time.<\/p>\n<p>While this is an interesting pattern, of course, no one prevents us from using different approaches such as RxJS that directly represent the flow of events.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is post 8 of 9 in the series &ldquo;Signals&rdquo; Signals in Angular: Building Blocks Component Communication with Signals: Inputs, Two-Way Bindings, and Content\/ View Queries Successful with Signals in Angular &#8211; 3 Effective Rules for Your Architecture Skillfully Using Signals in Angular &#8211; Selected Hints for Professional Use When (Not) to use Effects in [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":27915,"comment_status":"open","ping_status":"open","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":[18],"tags":[],"class_list":["post-27933","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","post_series-signals"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - 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\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"This is post 8 of 9 in the series &ldquo;Signals&rdquo; Signals in Angular: Building Blocks Component Communication with Signals: Inputs, Two-Way Bindings, and Content\/ View Queries Successful with Signals in Angular &#8211; 3 Effective Rules for Your Architecture Skillfully Using Signals in Angular &#8211; Selected Hints for Professional Use When (Not) to use Effects in [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2025-01-26T22:24:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-03T14:38:20+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/chat.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manfred Steyer, GDE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/chat.jpg\" \/>\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=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\"},\"author\":{\"name\":\"Manfred Steyer, GDE\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951\"},\"headline\":\"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World\",\"datePublished\":\"2025-01-26T22:24:19+00:00\",\"dateModified\":\"2025-06-03T14:38:20+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\"},\"wordCount\":1276,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\",\"name\":\"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg\",\"datePublished\":\"2025-01-26T22:24:19+00:00\",\"dateModified\":\"2025-06-03T14:38:20+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg\",\"width\":1000,\"height\":395},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World\"}]},{\"@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":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - 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\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/","og_locale":"en_US","og_type":"article","og_title":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - ANGULARarchitects","og_description":"This is post 8 of 9 in the series &ldquo;Signals&rdquo; Signals in Angular: Building Blocks Component Communication with Signals: Inputs, Two-Way Bindings, and Content\/ View Queries Successful with Signals in Angular &#8211; 3 Effective Rules for Your Architecture Skillfully Using Signals in Angular &#8211; Selected Hints for Professional Use When (Not) to use Effects in [&hellip;]","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/","og_site_name":"ANGULARarchitects","article_published_time":"2025-01-26T22:24:19+00:00","article_modified_time":"2025-06-03T14:38:20+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/chat.jpg","type":"image\/jpeg"}],"author":"Manfred Steyer, GDE","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/chat.jpg","twitter_creator":"@daniel","twitter_misc":{"Written by":"Manfred Steyer, GDE","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/"},"author":{"name":"Manfred Steyer, GDE","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/15628efa7af4475ffaaeeb26c5112951"},"headline":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World","datePublished":"2025-01-26T22:24:19+00:00","dateModified":"2025-06-03T14:38:20+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/"},"wordCount":1276,"commentCount":0,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/","name":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg","datePublished":"2025-01-26T22:24:19+00:00","dateModified":"2025-06-03T14:38:20+00:00","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2025\/01\/shutterstock_610351277.jpg","width":1000,"height":395},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/streaming-resources-for-a-chat-with-web-sockets-messages-in-a-glitch-free-world\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"Streaming Resources for a Chat with Web Sockets: Messages in a Glitch-Free World"}]},{"@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\/27933","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=27933"}],"version-history":[{"count":10,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/27933\/revisions"}],"predecessor-version":[{"id":30466,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/27933\/revisions\/30466"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/27915"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=27933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=27933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=27933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}