<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/atom-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0">
  <feedpress:locale>en</feedpress:locale>
  <link rel="hub" href="https://feedpress.superfeedr.com/"/>
  <logo>https://static.feedpress.com/logo/telerik-blogs-web-angular-61850c76637b3.jpg</logo>
  <title type="text">Telerik Blogs | Web | Angular</title>
  <subtitle type="text">The official blog of Progress Telerik - expert articles and tutorials for developers.</subtitle>
  <id>uuid:8773e822-51d4-4202-9c00-e67ef2cf3518;id=1550</id>
  <updated>2026-04-08T22:07:51Z</updated>
  <link rel="alternate" href="https://www.telerik.com/"/>
  <link rel="self" type="application/atom+xml" href="https://feeds.telerik.com/blogs/web-angular"/>
  <entry>
    <id>urn:uuid:9bf61f7e-e7a4-44d4-aba4-e8c1fc74615b</id>
    <title type="text">Progress Telerik Agentic UI Generator vs. Syncfusion Agentic UI Builder</title>
    <summary type="text">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head.</summary>
    <published>2026-04-08T16:38:33Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Hassan Djirdeh </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17315935/progress-telerik-agentic-ui-generator-vs-syncfusion-agentic-ui-builder"/>
    <content type="text"><![CDATA[<p><span class="featured">See how the AI-based UI creation tools from devtools powerhouses Progress and Syncfusion stack up when they go head to head. </span></p><p>AI-powered code generation has become a significant part of how developers build user interfaces. The <a target="_blank" href="https://survey.stackoverflow.co/2025/ai/#1-ai-tools-in-the-development-process">2025 Stack Overflow Developer Survey</a> found that 84% of developers are now using or planning to use AI tools in their development process.</p><p>Original AI adoption has been through tools like code autocompletion and chat-based assistants, but agentic UI tools take things further. Rather than suggesting the next line of code, they can take a natural language prompt and produce working, styled UI code in seconds.</p><p>However, not all AI generation tools are created equal. The quality of the output, how reliably it builds on the first attempt, how fast it runs and how well it handles things like accessibility and theming can vary quite a bit between tools. These differences matter because a tool that requires a large number of follow-up prompts to correct errors or produce code that doesn&rsquo;t match the original requirements isn&rsquo;t truly saving us time.</p><p>In this article, we&rsquo;ll look at a head-to-head comparison between two agentic UI generation tools: the <strong>Progress Telerik Agentic UI Generator</strong> which includes the <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Blazor Agentic UI Generator for .NET/Blazor</a> and the <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular and React</a>, and the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/"><strong>Syncfusion Agentic UI Builder</strong></a>. We&rsquo;ll walk through the results of extensive testing across multiple frameworks, covering output quality, performance, stability, accessibility, theming and more.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/progress-vs-syncfusion.jpg?sfvrsn=d281e72b_2" alt="Progress Telerik vs. Syncfusion" /></p><h2 id="how-the-comparison-was-conducted">How the Comparison Was Conducted</h2><p>To make this comparison as fair and thorough as possible, both tools were tested across multiple frameworks using two evaluation approaches.</p><h3 id="blazor.net">Blazor/.NET</h3><p>On the Blazor/.NET side, 23 prompts were run through the Telerik Agentic UI Generator and the Syncfusion Agentic UI Builder. These prompts ranged from simple single-component requests to complex multi-section layouts like e-commerce catalog pages and CMS admin dashboards. Each prompt&rsquo;s output was rated on a 0 to 7 scale:</p><ul><li><strong>0-1</strong>: Doesn&rsquo;t build or crashes with no UI</li><li><strong>2-3</strong>: Partially renders, major sections broken</li><li><strong>4</strong>: Renders but requires multiple prompts to clear build or runtime errors</li><li><strong>5</strong>: Renders but doesn&rsquo;t match prompt requirements in several areas</li><li><strong>6</strong>: Mostly complete, minor issues</li><li><strong>7</strong>: Fully matches requirements</li></ul><p>The evaluation also tracked how many prompts were needed before the output could successfully build and render, as well as the time (in seconds) from initial prompt submission to output generation.</p><h3 id="angular-and-react">Angular and React</h3><p>For Angular and React, a dedicated evaluation was conducted comparing the Kendo Agentic UI Generator against the Syncfusion Agentic UI Builder. Rather than scoring individual prompts, this evaluation focused on a technical comparison of the tools themselves. By running many prompts and examining the context returned by each tool, the analysis compared how each MCP server helps the AI agent arrive at its output across categories like layout, styling, accessibility, documentation and component handling.</p><h2 id="output-quality-and-reliability">Output Quality and Reliability</h2><p>This is the category where the gap between the two tools becomes immediately clear.</p><p>Across the 23 Blazor prompts, the Telerik Agentic UI Generator consistently produced complete, requirement-matching output on the first attempt. The Syncfusion Agentic UI Builder told a different story. It experienced <strong>five failures</strong> where no usable UI was generated at all, and several other prompts that required follow-up prompts to fix errors before the output could even build. Let&rsquo;s look at a couple of examples.</p><h3 id="failures">Failures</h3><p>The very first prompt asked both tools to build a login screen with email/password validation and an admin dashboard with a sidebar menu, key metrics and recent activity.</p><p><strong>Prompt</strong>: <em>&ldquo;I have created an empty application that now needs a login screen and an admin dashboard. Add a login form with email/password fields and validation. After a successful login, redirect to an admin dashboard page featuring a sidebar menu and a main content area displaying key metrics and recent activity.&rdquo;</em></p><p>The Telerik Generator produced a fully working output on the first attempt.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-1.png?sfvrsn=ead93eba_1" alt="Telerik UI Generator produced dashboard" /></p><p>The Syncfusion Builder returned an error along the lines of: <code>Error. This response is truncated because it is too long. Try rephrasing your question.</code> No UI was generated at all.</p><p>The second prompt told both tools to create a monitoring dashboard with system health KPIs, a log stream panel, charts for API response times and requests per service.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a new page using the existing top navigation and footer. In the middle, add 3 rows with 3 responsive columns each. The top row shows system health KPIs for CPU, memory and error counts. The middle rows include a Log Stream panel, a line Chart of API response times and a bar chart of requests per service. The bottom row contains a Deployment History table, an Alerts panel and a list of open tickets.&rdquo;</em></p><p>The Telerik Generator again produced a fully working output on the first pass.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-2.png?sfvrsn=150ecc0b_1" alt="Telerik Generator produced dashboard with graphs" /></p><p>The Syncfusion Builder hit the same truncation error.</p><p>These are the kinds of prompts that represent real-world use cases. A login screen with a dashboard and a monitoring page with multiple data panels aren&rsquo;t unusual requests.</p><h3 id="errors-requiring-follow-ups">Errors Requiring Follow-ups</h3><p>Not every issue is an error during the generation process. Some prompts produced output that needed additional work to get running.</p><p>We fired a prompt to ask for a product catalog page with a responsive layout, product cards, a filtering toolbar and expandable detail views. The Telerik Generator handled it cleanly on the first attempt. The Syncfusion Builder hit an error about a missing component parameter and needed a second follow-up prompt to fix it.</p><p><strong>Prompt</strong>: <em>&ldquo;Create a product catalog page with a responsive CSS layout. The layout should display product cards. Add a toolbar with filtering options, and expandable detail view for each product that work seamlessly on mobile, tablet, and desktop.&rdquo;</em></p><p>The first output by the Telerik Blazor generator:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-4.png?sfvrsn=5b3d958b_1" alt="Telerik Blazor AI UI Generator produced product catalog" /></p><p>The final output from Syncfusion, after the necessary follow-up prompt:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-4.png?sfvrsn=a91f64f0_1" alt="Syncfusion product catalog" /></p><p>The Syncfusion Builder&rsquo;s errors in these cases often involved referencing component parameters that don&rsquo;t exist, which may suggest the tool&rsquo;s AI agent is working with less reliable component information during generation.</p><h3 id="partial-results">Partial Results</h3><p>Not all issues showed up as crashes or errors needing follow-ups. Let&rsquo;s look at an example of a prompt that was made which involved a theming request.</p><p><strong>Prompt</strong>: <em>&ldquo;Generate a custom theme for a corporate blue and green color scheme with high contrast accessibility requirements.&rdquo;</em></p><p>The Telerik Agentic UI Generator created the output matching the requirements.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/blazor-agentic-ui-prompt-13.png?sfvrsn=ed53d11a_1" alt="Telerik Agentic UI generator blue n=and green" /></p><p>The Syncfusion Builder did create a custom theme, but the expected theme wasn&rsquo;t applied to the output.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-04/syncfusion-agentic-ui-prompt-13.png?sfvrsn=eaac1328_1" alt="Syncfusion green and blue missing" /></p><h3 id="the-bigger-picture">The Bigger Picture</h3><p>Even when we set aside the failures and only look at prompts where the Syncfusion Builder produced something usable, the outputs still frequently fell short of the original requirements.</p><p>On the Angular and React side, the findings were consistent. While the final rendered UI sometimes appeared similar at a glance, the most significant differences were in how each tool&rsquo;s MCP server helped the agent arrive at that output. The Kendo Generator&rsquo;s tools consistently delivered more relevant, targeted context to the AI agent, filtering results to what was actually needed for the prompt. The Syncfusion Builder&rsquo;s tools returned broader, less filtered responses, often including full component prop lists and governance rules regardless of what was asked.</p><h2 id="performance">Performance</h2><p>Speed matters when we&rsquo;re iterating on UI designs with AI. Waiting several minutes for a complex layout to generate can significantly slow down the development flow.</p><p>Across the Blazor evaluation, the Telerik Generator was consistently faster. The speed advantage was most noticeable on complex layout prompts. For example, on a complex e-commerce catalog page with filtering, sorting, responsive breakpoints and pagination, the Telerik Generator completed in about 799 seconds while the Syncfusion Builder took 908 seconds.</p><p>There was one outlier where Syncfusion was notably faster (a simpler single-component case), but across the full set of 23 prompts, the speed advantage consistently favored Telerik.</p><h2 id="accessibility">Accessibility</h2><p>Accessibility is often treated as an afterthought, but for enterprise applications, it&rsquo;s a requirement, not a nice-to-have!</p><p>The Kendo Generator includes a dedicated accessibility tool (<a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/prompt-library#accessibility-assistant">#kendo_accessibility_assistant</a>) that retrieves WCAG 2.2 Level AA guidelines as a mandatory step in the generation process. It also fetches component-specific accessibility requirements for each component used in the output. This leads to every piece of generated UI having accessibility considerations baked in from the start.</p><p>From what we can gather, and at the time of writing, the Syncfusion Builder doesn&rsquo;t have a strong accessibility tool like the <code>#kendo_accessibility_assistant</code>.</p><h2 id="theming-layout-and-documentation">Theming, Layout and Documentation</h2><p>Beyond output quality and speed, the Angular and React evaluation revealed some important architectural differences in how each tool handles theming, layout and documentation.</p><h3 id="theming">Theming</h3><p><strong>Theming</strong> is more than color selection. The Kendo UI Generator produces a complete design system from a single prompt, including colors, typography, spacing scales, border radius, elevation and shadows. The Syncfusion Builder&rsquo;s style tool is limited to component state colors and semantic colors. Typography, spacing and elevation aren&rsquo;t reachable through it, so the generated output may look right in terms of color but lack the design coherence that holds a full application together.</p><h3 id="layout">Layout</h3><p><strong>Layout</strong> is also where a notable dependency difference comes in. The Kendo UI Generator uses a self-contained layout system built on its own CSS utilities, introducing no external dependencies. The Syncfusion Builder relies on <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a>, injected into every project, and works from a catalog of 265+ prebuilt blocks. When the desired layout doesn&rsquo;t match a catalog entry, the result approximates what was asked for.</p><p>For teams already using Tailwind, this might feel natural but for projects on a different CSS framework (<a target="_blank" href="https://material.angular.dev/">Angular Material</a>, for example), adding Tailwind on top can introduce style conflicts. This can also be a potential blocker for organizations that restrict third-party dependencies.</p><p>Responsiveness follows a similar split: the Kendo UI Generator has a dedicated phase with explicit breakpoint reasoning, while the Syncfusion Builder inherits responsive behavior from Tailwind&rsquo;s defaults without any first-class responsive logic of its own.</p><h3 id="documentation">Documentation</h3><p><strong>Documentation</strong> plays a bigger role in output quality than it might seem, since it directly shapes how well the AI agent understands the components it&rsquo;s generating. The Kendo UI Generator injects relevant documentation chunks directly into every component tool call, including API references with full type signatures. The Syncfusion Builder treats documentation as a separate tool, triggered only by specific keywords. At the time of the evaluation, results from this tool were inconsistent and the service had been unavailable for over 24 hours for both Angular and React.</p><p>One other important observation from the Angular and React evaluation: the Kendo UI Generator customizes its workflow per prompt using confidence scores, including only the tools and instructions relevant to each request. The Syncfusion Builder runs the same fixed sequence for most prompts regardless of complexity, and its component tools return the full prop list and approximately 250 lines of governance rules on every call. The result is that <strong>the Kendo UI agent operates on targeted, preprocessed context while the Syncfusion agent carries a heavier payload for every request</strong>.</p><h2 id="wrap-up">Wrap-up</h2><p>The comparison across Blazor, Angular and React tells a consistent story with these agentic UI generators. The Progress Telerik Agentic UI Generator outperforms the Syncfusion Agentic UI Builder across output quality, reliability, performance, accessibility, theming, layout and documentation.</p><p>On the Blazor side, the Telerik Generator had zero full failures across 23 prompts while Syncfusion had five, along with a consistent speed advantage on complex prompts and more reliable first-pass output. On the Angular and React side, the advantages show up in the underlying architecture, where the Kendo Generator&rsquo;s tools consistently deliver cleaner, more relevant context to the AI agent.</p><hr /><blockquote><p>Get started with AI-empowered development. The <a target="_blank" href="https://www.telerik.com/mcp-servers">Kendo UI and Telerik AI tools</a> are ready. And they come as part of the free trial of the component libraries.</p><br /><p><a href="https://www.telerik.com/mcp-servers#how-to-try" class="Btn" target="_blank">Try Now</a></p></blockquote><hr /><p>For more information on the Progress Telerik Agentic UI Generator, check out the following resources:</p><ul><li><a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/getting-started">Telerik Agentic UI Generator for Blazor</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for Angular</a></li><li><a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">Kendo UI Generator for React</a></li></ul><p>The full comparison data referenced in this article is available for download:</p><ul><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-builder-vs-telerik-generator-comparison.xlsx">Telerik UI for Blazor Agentic UI Generator vs Syncfusion Agentic UI Builder Comparative Evaluation (XLSX)</a></li><li><a target="_blank" href="https://www.telerik.com/docs/default-source/blogs-docs//syncfusion-ui-builder-vs-kendo-ui-generator.xlsx">Kendo Agentic UI Generator vs Syncfusion Agentic UI Builder (XLSX)</a></li></ul><hr /><h2 id="summary-faqs">Summary FAQs</h2><h3 id="what-do-these-tools-do">What Do These Tools Do?</h3><h4 id="what-telerik-agentic-ui-generator-is">What Telerik Agentic UI Generator Is</h4><p>According to the <a href="https://www.telerik.com/mcp-servers" target="_blank">Progress Telerik website</a>, the Telerik Agentic UI Generator for Telerik and Kendo UI libraries is an intelligent development tool delivered through the Model Context Protocol (MCP) Server that enables UI generation from natural language prompts. Once configured and authenticated, you can use the Agentic UI Generator tool (#telerik_ui_generator) together with the available specialized MCP assistants.</p><h4 id="what-syncfusion-agentic-ui-builder-is">What Syncfusion Agentic UI Builder Is</h4><p>According to the <a target="_blank" href="https://www.syncfusion.com/explore/agentic-ui-builder/">Syncfusion site</a>, Syncfusion&rsquo;s Agentic UI Builder is designed to work inside an IDE to generate UIs, dashboards or pages with Syncfusion components with natural language commands. Syncfusion uses MCP integration to access component APIs, prebuilt UI blocks, styling configurations, icon libraries and code generation.</p><h3 id="why-does-mcp-matter-in-both-products">Why Does MCP Matter in Both Products?</h3><p>Both brands&rsquo; tools use Model Context Protocol (MCP) servers to connect AI applications directly to the software specs for the individual library. This means that the AI is informed on component documentation, best practices, workflows and tooling provided by the UI library, so the AI can create a user interface more in line with how the library was designed to work. It should result in better outputs than if an AI were cobbling together an interface without guidance.</p><p>Learn more about the individual MCP servers:</p><ul><li><a href="https://www.telerik.com/blazor-mcp-servers" target="_blank">Telerik UI for Blazor MCP Servers</a></li><li><a href="https://www.telerik.com/angular-mcp-servers" target="_blank">Kendo UI for Angular MCP Servers</a></li><li><a href="https://www.telerik.com/react-mcp-servers" target="_blank">KendoReact MCP Servers</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/overview">Syncfusion EJ2 React MCP Server</a></li><li><a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/overview">Syncfusion EJ2 Angular MCP Server</a></li><li><a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/overview">Syncfusion Blazor MCP Server</a></li></ul><h3 id="are-prompt-libraries-included">Are Prompt Libraries Included?</h3><h4 id="telerik-and-kendo-ui-generator-prompt-libraries">Telerik and Kendo UI Generator Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Kendo UI and Telerik AI UI Generator tools:</p><ul><li>Blazor: <a target="_blank" href="https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library">https://www.telerik.com/blazor-ui/documentation/ai/agentic-ui-generator/prompt-library</a></li><li>React: <a target="_blank" href="https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started">https://www.telerik.com/kendo-react-ui/components/ai-tools/agentic-ui-generator/getting-started</a></li><li>Angular: <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library">https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/prompt-library</a></li></ul><h4 id="syncfusion-agentic-ui-builder-prompt-libraries">Syncfusion Agentic UI Builder Prompt Libraries</h4><p>Yes! Prompt libraries are included for the Syncfusion Agentic UI Builder tools:</p><ul><li>Blazor: <a target="_blank" href="https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library">https://blazor.syncfusion.com/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>React: <a target="_blank" href="https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/react/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li><li>Angular: <a target="_blank" href="https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library">https://ej2.syncfusion.com/angular/documentation/mcp-server/agentic-ui-builder/prompt-library</a></li></ul><img src="https://feeds.telerik.com/link/23055/17315935.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:8adaf186-7275-4dfe-8fbd-0e63950051ac</id>
    <title type="text">Build Accessible Components with Angular Aria</title>
    <summary type="text">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives. Take a look.</summary>
    <published>2026-04-01T19:25:26Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17311879/build-accessible-components-angular-aria"/>
    <content type="text"><![CDATA[<p><span class="featured">A simple way to add accessibility to your Angular app is with Angular Aria, which gives you production-ready, WCAG-compliant directives.</span></p><p>Building accessible components is one of those things we know we <em>should</em> do, but often skip because it feels overwhelming. We need to <a target="_blank" href="https://www.telerik.com/blogs/improving-navigation-accessibility-4-quick-tips">read about accessibility tips and tricks</a> and a lot of documentation.</p><p>You start with a simple dropdown menu, knowing you need to handle keyboard navigation, ARIA attributes, focus management and screen reader support. Before you know it, your &ldquo;simple&rdquo; component has 200 lines of accessibility code you&rsquo;re not even sure is correct. (Unless you&rsquo;re using the Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Angular library</a>, which has accessibility baked in for you. )</p><p>What if I told you there&rsquo;s a way to get the accessibility magic you need, regardless of component library, with full control over your styling with the magic of <a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria</a>?</p><p>But what is Angular Aria? Let&rsquo;s make a small intro.</p><h2 id="what-is-angular-aria">What Is Angular Aria?</h2><p>Think of Angular Aria as a collection of accessibility superpowers for your components, but instead of manually implementing keyboard navigation, ARIA attributes and focus management, you import a directive, add it to your HTML and, boom, your component is accessible.</p><p>The Angular team built these directives following the <a target="_blank" href="https://www.w3.org/WAI/ARIA/apg/">W3C Accessibility Guidelines</a>, so you don&rsquo;t have to become an accessibility expert to build compliant components.</p><h2 id="hold-on-what-about-angular-material">Hold On, What About Angular Material?</h2><p>Great question! If you&rsquo;ve been using Angular for a while, you&rsquo;re probably thinking: <em>&ldquo;We already have <a target="_blank" href="https://material.angular.io/">Angular Material</a>. Why do we need another library?&rdquo;</em></p><p>Here are the key differences:</p><p>Angular Material gives you complete, prestyled components. They look great out of the box, but they come with Material Design opinions baked in. If you want a button that doesn&rsquo;t look like a Material button, you&rsquo;re going to fight the framework.</p><p>Angular Aria gives you headless directives&mdash;just the accessibility logic, zero styling. You get all the keyboard navigation, ARIA attributes and screen reader support, but you control every pixel of how it looks.</p><p>Think of it this way:</p><ul><li>Angular Material: It is plug and play, looks good, works immediately, but everyone has the same result. If you were building a physical doorway to your business, it would look like all other businesses, just with your business name on the sign.</li><li>Angular Aria: This tool is more like the ramp to your front door, enabling anyone to access the business entrance, while allowing you to choose the awning, the window display and the door color.</li></ul><p>So when should you use each one? We&rsquo;ll dive deeper into that later in the article, but here&rsquo;s the quick answer:</p><ul><li>Use <strong>Angular Material</strong> when you need to ship fast and Material Design works for you.</li><li>Use <strong>Angular Aria</strong> when you have custom design requirements and need full control.</li></ul><p>Remember, accessibility isn&rsquo;t optional anymore. It&rsquo;s a <a target="_blank" href="https://www.telerik.com/blogs/what-does-european-accessibility-act-mean-developers">legal requirement</a> in many countries, and, more importantly, it&rsquo;s the right thing to do.</p><p>But implementing accessibility correctly is <strong>hard</strong>. You need to know:</p><ul><li>Which ARIA attributes to use (and when)</li><li>How keyboard navigation should work for each pattern</li><li>How to manage focus properly</li><li>How screen readers interpret your markup</li></ul><p>Angular Aria handles this complexity for you. You focus on the HTML structure, CSS styling and business logic, and Angular Aria takes care of accessibility.</p><p>But, as always, the best way to learn is by building something. Let&rsquo;s do it!</p><h2 id="set-up-the-project">Set Up the Project</h2><p>First, create a new Angular application. In your terminal, run the following command (be sure to have Node.js installed).</p><pre class=" language-bash"><code class="prism  language-bash">npx @angular/cli@latest new angular-aria-demo
</code></pre><p>When CLI prompts stylesheet format, pick CSS.</p><pre class=" language-bash"><code class="prism  language-bash">  - **Which stylesheet <span class="token function">format</span> would you like to use?** &rarr; CSS
</code></pre><p>Now, navigate to your project and add Angular Aria:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">cd</span> angular-aria-demo
<span class="token function">npm</span> <span class="token function">install</span> @angular/aria
</code></pre><p>That&rsquo;s it. We now have a fresh Angular project with Angular Aria installed. Let&rsquo;s build something accessible!</p><h2 id="building-an-accessible-toolbar">Building an Accessible Toolbar</h2><p>Let&rsquo;s build a text formatting toolbar, the kind you see in rich text editors. This is a perfect example because it looks simple but has surprising accessibility complexity.</p><p>Using the CLI, generate a new component editor-toolbar:</p><pre class=" language-bash"><code class="prism  language-bash">ng generate c components/editor-toolbar
</code></pre><p>Perfect! Open the component with your editor, and import <code>Toolbar</code>, <code>ToolbarWidget</code> and <code>ToolbarWidgetGroup</code> directives provided by <code>@angular/aria/toolbar</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript">  <span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
  <span class="token keyword">import</span> <span class="token punctuation">{</span> Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/aria/toolbar'</span><span class="token punctuation">;</span>
  
  @<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    selector<span class="token punctuation">:</span> <span class="token string">'app-editor-toolbar'</span><span class="token punctuation">,</span>
    templateUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.html'</span><span class="token punctuation">,</span>
    styleUrl<span class="token punctuation">:</span> <span class="token string">'./editor-toolbar.component.css'</span><span class="token punctuation">,</span>
    imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>Toolbar<span class="token punctuation">,</span> ToolbarWidget<span class="token punctuation">,</span> ToolbarWidgetGroup<span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">EditorToolbarComponent</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p>Now it&rsquo;s time to build the HTML structure. We create a div container with the directive <code>[ngToolbar]</code>, which works as the main container. We also need <code>ToolbarWidget</code> to use with individual buttons and <code>ToolbarWidgetGroup</code> for groups of related buttons.</p><p>In the following HTML, we use every directive with divs and button elements. Copy it and paste into the <code>editor-toolbar.html</code>.</p><pre class=" language-html"><code class="prism  language-html">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ngToolbar</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Text Formatting Tools<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>undo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Undo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>redo<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Redo
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token comment">&lt;!-- Text formatting group --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold<span class="token punctuation">"</span></span>
           <span class="token attr-name">#bold</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-pressed]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bold.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Bold
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic<span class="token punctuation">"</span></span>
           <span class="token attr-name">#italic</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-pressed]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>italic.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Italic
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>separator<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

 <span class="token comment">&lt;!-- Alignment group (radio buttons) --&gt;</span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">ngToolbarWidgetGroup</span>
      <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radiogroup<span class="token punctuation">"</span></span>
      <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>group<span class="token punctuation">"</span></span>
      <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Text alignment options<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align left<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align left<span class="token punctuation">"</span></span>
           <span class="token attr-name">#leftAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>leftAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Left
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align center<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align center<span class="token punctuation">"</span></span>
           <span class="token attr-name">#centerAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>centerAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Center
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">ngToolbarWidget</span>
           <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span>
           <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span>
           <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align right<span class="token punctuation">"</span></span>
           <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>align right<span class="token punctuation">"</span></span>
           <span class="token attr-name">#rightAlign</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ngToolbarWidget<span class="token punctuation">"</span></span>
           <span class="token attr-name">[aria-checked]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>rightAlign.selected()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     Right
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The final step is adding some CSS styles to make it look nice. Open the editor-toolbar.css and paste the following style:</p><pre class=" language-css"><code class="prism  language-css">  <span class="token selector"><span class="token attribute">[ngToolbar]</span> </span><span class="token punctuation">{</span>
 <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
 <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
 <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">8</span>px<span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#f5f5f5</span><span class="token punctuation">;</span>
 <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.group</span> </span><span class="token punctuation">{</span>
 <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
 <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.separator</span> </span><span class="token punctuation">{</span>
 <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">1</span>px<span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#ddd</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button </span><span class="token punctuation">{</span>
 <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token number">8</span>px <span class="token number">12</span>px<span class="token punctuation">;</span>
 <span class="token property">border</span><span class="token punctuation">:</span> <span class="token number">1</span>px solid <span class="token hexcode">#ddd</span><span class="token punctuation">;</span>
 <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
 <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">4</span>px<span class="token punctuation">;</span>
 <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button<span class="token attribute">[aria-pressed="true"]</span>,
button<span class="token attribute">[aria-checked="true"]</span> </span><span class="token punctuation">{</span>
 <span class="token property">background</span><span class="token punctuation">:</span> <span class="token hexcode">#007acc</span><span class="token punctuation">;</span>
 <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Perfect, we just added HTML, CSS and Angular Aria directives. To test it, open the app.html and add <code>&lt;app-editor-toolbar&gt;&lt;/app-editor-toolbar&gt;</code>, save changes and run your app.</p><pre class=" language-bash"><code class="prism  language-bash">ng serve
Initial chunk files <span class="token operator">|</span> Names         <span class="token operator">|</span> Raw size
main.js             <span class="token operator">|</span> main          <span class="token operator">|</span> 10.50 kB <span class="token operator">|</span> 
styles.css          <span class="token operator">|</span> styles        <span class="token operator">|</span> 95 bytes <span class="token operator">|</span> 

                    <span class="token operator">|</span> Initial total <span class="token operator">|</span> 10.59 kB

Application bundle generation complete. <span class="token punctuation">[</span>0.641 seconds<span class="token punctuation">]</span> - 2026-01-25T10:16:33.843Z

Watch mode enabled. Watching <span class="token keyword">for</span> <span class="token function">file</span> changes<span class="token punctuation">..</span>.
NOTE: Raw <span class="token function">file</span> sizes <span class="token keyword">do</span> not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show <span class="token function">help</span>
</code></pre><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/keyboard-navigating-buttons.gif?sfvrsn=b37b8cd8_8" alt="User navigates buttons with keyboard arrow keys" /></p><p>Try to use your toolbar with your keyboard. You&rsquo;ll find it works, and we didn&rsquo;t have to write any code for keyboard navigation logic (like: Arrow keys, Home, End), focus management, ARIA role attributes, screen reader announcements or selection state management. All of that complexity? Gone.</p><p>The <code>ngToolbar</code>, <code>ngToolbarWidget</code> and <code>ngToolbarWidgetGroup</code> directives handle all of that automatically.</p><p>We now have a fully accessible toolbar that works with keyboard navigation and screen readers, and we only wrote the HTML structure and CSS.</p><p>Angular Aria provides directives for the most common interactive patterns, we can get components for search and selection (like Autocomplete, Listbox and Select), navigation and actions (Menu, Menubar and Toolbar like we just built), and content organization (Accordion, Tabs, Tree and Grid). Every directive comes with complete documentation, working examples and API references. You can see the <a target="_blank" href="https://angular.dev/guide/aria/overview#whats-included">full list of available components</a> in the official Angular Aria documentation.</p><h2 id="but-im-a-fan-of-angular-material">But I&rsquo;m a Fan of Angular Material</h2><p>Yes, I understand Angular Material has a long relationship with Angular devs. You can continue using Angular Material when you:</p><ol><li><strong>Need to ship fast</strong> &ndash; You&rsquo;re building an MVP or internal tool and don&rsquo;t want to spend time on custom styling.</li><li><strong>Like Material Design</strong> &ndash; You&rsquo;re OK with the Google Material Design aesthetic.</li><li><strong>Have limited design resources</strong> &ndash; Your team doesn&rsquo;t have dedicated designers.</li></ol><p>Remember, <a target="_blank" href="https://material.angular.io/">Angular Material</a> is amazing, but it comes with opinions about how things should look.</p><p>If you try to heavily customize Material components, you&rsquo;ll spend more time fighting the framework than building features. I&rsquo;ve been there&mdash;overriding Material styles with <code>::ng-deep</code> and <code>!important</code> until the CSS becomes unmaintainable.</p><p>And don&rsquo;t even get me started on theming. Creating a custom theme for Angular Material is&hellip; let&rsquo;s just say &ldquo;special.&rdquo; It&rsquo;s doable, but it&rsquo;s tricky and requires deep knowledge of Sass and Material&rsquo;s theming system. (If you&rsquo;re curious about the complexity, I wrote about it in <a target="_blank" href="https://www.telerik.com/blogs/theme-ui-frameworks-angular-part-2-custom-theme-angular-material">Theme UI Frameworks in Angular: Part 2 - Custom Theme for Angular Material</a>.)</p><p>Angular Aria solves this by giving you <strong>zero styles</strong>. You start with a blank canvas and build exactly what you need.</p><p>Remember for simple cases, native elements are already accessible when you use <code>&lt;button&gt;</code> for buttons, <code>&lt;input type="radio"&gt;</code> for radio buttons or <code>&lt;select&gt;</code> for simple dropdowns. But Angular Aria gives you a third option: <strong>headless accessible components</strong> that you can style however you want, we can meet accessibility requirements, maintain full design control and avoid reinventing the wheel.</p><h2 id="recap">Recap</h2><p>We learned that accessibility doesn&rsquo;t have to be overwhelming. Angular Aria gives you production-ready, WCAG-compliant directives that handle the complex parts.</p><p>We provide the HTML structure and CSS and Angular Aria provides the accessibility without pain!</p><h3 id="but-what-about-kendo-ui">But What About Kendo UI?</h3><p>Maybe you want to ship faster (really fast) and have complex scenarios with datalist, charts, schedulers and complex UI patterns. If you read this article and are thinking: <em>&ldquo;This is great, but I still have to write all the HTML and CSS myself. Why not just use a complete component library?&rdquo;</em> you&rsquo;re asking the right question.</p><p>Here&rsquo;s when Progress <strong>Kendo UI for Angular</strong> makes more sense than Angular Aria or Angular Material:</p><p><strong>Use Kendo UI when you want:</strong></p><ol><li><strong>Everything out of the box</strong> &ndash; Prebuilt components with professional styling, themes and accessibility already done</li><li><strong>Advanced features included</strong> &ndash; Things like data grids with sorting/filtering, charts, schedulers and complex UI patterns</li><li><strong>Consistent design system</strong> &ndash; A cohesive look across all components without writing custom CSS</li><li><strong>Enterprise-grade support</strong> &ndash; Professional support, regular updates and guaranteed compatibility</li><li><strong>Speed PLUS customization</strong> &ndash; You need to ship fast <em>and</em> need options to customize (you&rsquo;ll have five fully built theme options plus the ability to tweak those or create your own theme)</li></ol><p>There&rsquo;s no &ldquo;wrong&rdquo; choice&mdash;just different tools for different jobs.</p><p>If you&rsquo;re building internal tools or you like the Kendo UI design system, Kendo UI saves you weeks of work, and, honestly? I can build complex stuff (data grids, schedulers, charts) in minutes, making Kendo UI the right answer for me.</p><p>Plus, you can use the Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Angular AI Coding Assistant</a>, an MCP server that automatically scaffolds components for AI agents. Instead of manually writing Kendo UI components, your AI assistant can do it for you. </p><blockquote><p>Want to learn more? Check out my article: <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">
 Angular and Kendo UI MCP: Making Agents Work for You</a></p></blockquote><ul><li><a target="_blank" href="https://github.com/danywalls/angular-aria-example">Source code</a></li><li><a target="_blank" href="https://angular.dev/guide/aria/overview">Angular Aria Documentation</a></li></ul><img src="https://feeds.telerik.com/link/23055/17311879.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:3c8c4ee0-cf8c-4226-b0de-9aa709b3a16e</id>
    <title type="text">Top 3 Everyday Angular Tasks That MCP Servers Automate for You</title>
    <summary type="text">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here’s how MCP can help.</summary>
    <published>2026-03-24T21:04:24Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Alyssa Nicoll </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17305464/top-3-everyday-angular-tasks-mcp-servers-automate"/>
    <content type="text"><![CDATA[<p><span class="featured">Scaffolding, creating UI from ideas and data, iterating and updating. These are things every Angular developer does, and here&rsquo;s how MCP can help. </span></p><p>Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and adjusting layouts. Or, at least they used to, before the age of AI.</p><p>Now, MCP-powered tools can automate much of that work&mdash;letting coding assistants generate Angular code and tools like Agentic UI Generator turn prompts or data into working UI so developers can move faster.</p><blockquote><p>&ldquo;AI made refactoring and handling technical debt much faster, allowing us to focus on market features. Validating ideas, creating POCs, and writing tests are also areas where we&rsquo;ve seen huge impact. The whole development lifecycle changed, and it opened the door for exploration and innovation.&rdquo;<br />&mdash; Progress Product Team Insight</p></blockquote><p><strong>Model Context Protocol (MCP)</strong> is a way for AI assistants to connect directly to tools and dev environments instead of generating code in isolation.</p><p>Without that connection, AI can only make suggestions based on patterns it has seen before. It doesn&rsquo;t know what Angular version you&rsquo;re using, what components exist in your UI library or what APIs are actually available in your project. (Unless your assistant is built into a full-blown IDE, like <a href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular" target="_blank">Cursor</a>.)</p><p>Often, with AI, the output might look correct, but developers end up fixing hallucinated APIs or rewriting scaffolding to make it fit their app. MCP closes that gap by giving AI access to real context&mdash;frameworks, component libraries, project structure and tooling. Instead of guessing what code might work, the assistant can generate output grounded in the tools you&rsquo;re actually using.</p><p>So if you love VS Code, for example, but Copilot just isn&rsquo;t cutting it for frontend AI-generated code, this is where MCP can fill the gap.</p><p>This is especially true for frontend work. Angular developers spend a lot of time on repetitive UI tasks like scaffolding components, wiring data into views and configuring layouts. MCP-powered tools can automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like Agentic UI Generator can turn prompts or data into working UI.</p><p>The result isn&rsquo;t magic code generation&mdash;it&rsquo;s a faster starting point. AI helps developers get moving, while humans still shape the final result.</p><h2 id="task-1-scaffolding-angular-components-faster">Task #1: Scaffolding Angular Components Faster</h2><p>Creating components is one of the most common tasks in Angular development. Even with Angular CLI, developers still need to generate the component, add inputs, wire services and start building the template.</p><p>If your coding assistant is connected to the Progress <strong><a target="_blank" href="https://www.telerik.com/angular-mcp-servers">Kendo UI for Angular MCP server</a></strong>, it understands the components available in your UI library and can generate valid Angular structures using them.</p><p>With an MCP-powered coding assistant, you can start with a simple prompt:</p><pre class=" language-javascript"><code class="prism  language-javascript">#kendo_component_assistant Create a ProductCard Angular component that displays a product image<span class="token punctuation">,</span>
name<span class="token punctuation">,</span> and price using Kendo UI components<span class="token punctuation">.</span>
</code></pre><p>The assistant can generate a working Angular component structure:</p><pre class=" language-javascript"><code class="prism  language-javascript">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-product-card'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_LAYOUT<span class="token punctuation">,</span> NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> `
    <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-card"</span> width<span class="token operator">=</span><span class="token string">"100%"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span>img
        kendoCardMedia
        <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageUrl"</span>
        <span class="token punctuation">[</span>width<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageWidth"</span>
        <span class="token punctuation">[</span>height<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageHeight"</span>
        <span class="token punctuation">[</span>alt<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"product().imageAlt"</span>
      <span class="token operator">/</span><span class="token operator">&gt;</span>

      <span class="token operator">&lt;</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h3 kendoCardTitle<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">product</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>p <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"product-price"</span> <span class="token punctuation">[</span>attr<span class="token punctuation">.</span>aria<span class="token operator">-</span>label<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"'Price: ' + formattedPrice()"</span><span class="token operator">&gt;</span>
          <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">formattedPrice</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">-</span>body<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>kendo<span class="token operator">-</span>card<span class="token operator">&gt;</span>
    <span class="token operator">...</span>
</code></pre><p>Instead of starting from scratch, developers get a <strong>valid Angular starting point immediately</strong> and can focus on refining the UI.</p><h2 id="task-2-turning-data-into-ui">Task #2: Turning Data Into UI</h2><p>A large portion of frontend work isn&rsquo;t writing complex logic&mdash;it&rsquo;s translating data and ideas into working UI.</p><p>As devs, we are accustomed to taking API responses or product requirements and turn them into forms, dashboards or application layouts. That process usually starts with sketching the structure of the interface and then building the components to support it.</p><p>With the <strong><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/agentic-ui-generator/getting-started">Angular Agentic UI Generator</a></strong>, you can start that process with a prompt instead.</p><p>Because the tool connects to your UI library through MCP, it understands the components available in your stack and can generate layouts using them. Instead of manually assembling the structure of the page, the generator produces a working Angular layout you can refine.</p><p>For example, you might start with a prompt like this:</p><blockquote><p>#kendo-ui-generator Create a responsive Workflow Composer app layout that includes: a left sidebar that only takes up 1/3 max of the UI for available workflow steps (this is essentially a column that is a list of individual cards/tasks), and main canvas area for building connected flows.</p></blockquote><p>From there, the generator produces a starting UI layout using Kendo UI for Angular components.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/workflow-composer.png?sfvrsn=7250b55a_2" alt="Workflow Composer shows steps for start, webhook trigger, output" /></p><h2 id="task-3-updating-and-iterating-on-ui">Task #3: Updating and Iterating on UI</h2><p>Building the first version of a UI is only the beginning. Most frontend work happens in the iteration phase&mdash;adjusting layouts, adding interactions and refining components as requirements evolve.</p><p>This is another area where MCP-connected assistants can help speed things up. Instead of manually digging through templates and wiring new behavior, developers can describe the change they want and let the assistant update the structure.</p><p>For this last task, I took our generated Workflow Composer app and added drag-and-drop support with a simple prompt:</p><blockquote><p>#kendo_ui_generator let&rsquo;s add drag and drop</p></blockquote><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/ui-generator-add-drag-drop.png?sfvrsn=29ecb3c0_2" alt="kendo_ui_generator let&#39;s add drag and drop" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/drag-drop-workflow.gif?sfvrsn=a5876330_1" alt="Workflow Composer now has drag and drop. User adds steps to the workflow in seconds." /></p><p>Rather than rewriting the layout or manually integrating interaction logic, the assistant extends the generated UI and adds the new behavior.</p><p>One thing I&rsquo;ve noticed while experimenting with this workflow is that <strong>single task prompts tend to work best</strong>. Breaking changes into bite-sized requests often produces cleaner results when working with MCP-powered tools and Copilot.</p><h2 id="why-mcp-matters">Why MCP Matters</h2><p>AI coding tools are useful, but without access to your real development environment, they can only generate suggestions based on patterns they&rsquo;ve seen before.</p><p>MCP changes that by connecting AI assistants directly to the tools developers already use. Instead of guessing which components exist or how your project is structured, the assistant can interact with real frameworks, libraries and development workflows.</p><p>That connection is what makes tasks like generating Angular components, creating UI layouts or iterating on interfaces possible with simple prompts. Rather than starting from scratch each time, devs get a working starting point that fits their stack.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular and Kendo UI MCP: Making Agents Work for You</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Keep reading: See what&rsquo;s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for <a target="_blank" href="https://www.telerik.com/blogs/angular-kendo-ui-mcp-making-agents-work">Angular AI Coding Assistant can connect with the Angular MCP Server</a> in a truly intelligent way.</p></div></div><hr class="u-mb3" /></aside><h2 id="conclusion">Conclusion</h2><p>Angular developers spend a lot of time on repetitive UI work&mdash;scaffolding components, turning data into layouts and iterating on interfaces as requirements evolve.</p><p>MCP-powered tools can help automate much of that groundwork. Coding assistants can generate valid Angular structures, and tools like the <strong>Angular Agentic UI Generator</strong> can turn prompts into working UI layouts that developers can refine and extend.</p><p>If you&rsquo;d like to try it yourself, you can install our MCP servers and learn how to get started with <strong>Coding Assistant</strong> and <strong>Agentic UI Generator</strong> in the documentation.</p><p> <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/installation">Explore the MCP setup guide in the docs.</a></p><img src="https://feeds.telerik.com/link/23055/17305464.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:83355cb1-6aa7-4e16-a1ad-a46f9c085158</id>
    <title type="text">Angular and Kendo UI MCP: Making Agents Work for You</title>
    <summary type="text">See what’s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for Angular AI Coding Assistant can connect with the Angular MCP Server in a truly intelligent way.</summary>
    <published>2026-03-18T18:51:53Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17301664/angular-kendo-ui-mcp-making-agents-work"/>
    <content type="text"><![CDATA[<p><span class="featured">See what’s possible when your AI assistant can use your actual tools to perform work for you: The Kendo UI for Angular AI Coding Assistant can connect with the Angular MCP Server in a truly intelligent way.</span></p>
<p>Building modern Angular applications involves juggling multiple tasks: executing CLI commands, managing libraries, navigating documentation and, now, integrating AI tools.</p>
<p>The challenge? Most AI assistants provide generic code snippets but lack context about your specific project structure or the professional UI tools you use.</p>
<p>What if your AI assistant could do more than just suggest code? What if it could actually use your tools to perform the work for you? Imagine an agent that doesn’t just “talk” about Angular and Kendo UI documentation but actually applies official best practices directly to your codebase.</p>
<p>Today, we’re going to bridge that gap. We’ll connect your AI tools directly to your project to literally <strong>make Angular and Kendo UI work for you</strong>.</p>
<p>We’ll achieve this using <a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP</a> and the Progress <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo UI for Angular AI Coding Assistant</a>.</p>
<h2 id="but-first-what-is-mcp">But First, What Is MCP?</h2>
<p>MCP stands for <strong>Model Context Protocol</strong>. Think of it as a standardized bridge that allows AI assistants to securely interact with your local tools and data.</p>
<p>Before MCP, interacting with an AI was like having a video call with a senior developer; they could offer great advice, but they couldn’t touch your keyboard. With MCP our reality changes, MCP brings a standard way for AI to connect with our source code; enabling it to execute commands, read files and understand the state of your project in real time and give full access and context to help us.</p>
<p>For a deeper dive into the concept, I recommend checking out <a target="_blank" href="https://www.telerik.com/blogs/promise-model-context-protocol">The Promise of Model Context Protocol</a>.</p>
<p>By combining <strong>Angular MCP</strong> for project management and the <strong>Kendo UI for Angular AI Coding Assistant</strong> for professional UI components, we can transform the development experience. We stop typing <code>ng generate</code> commands manually and stop switching context so we can see Kendo UI documentation inside our editor by following the Progress team’s recommended practices.</p>
<p>Let’s talk first about Angular MCP!</p>
<h2 id="part-1-angular-mcp-the-builder">Part 1: Angular MCP (The Builder)</h2>
<p>Think of <strong>Angular MCP</strong> as a direct line between your AI-powered editor (like Cursor or VS Code) and the Angular CLI.</p>
<p>Instead of switching to a terminal, you can simply ask your AI to create a new component called <code>user-profile</code>, add <code>@angular/material</code> to your project, or fix a build error and explain what happened.</p>
<p>We need to register the MCP server in your editor’s configuration. In <strong>Cursor</strong>, open your MCP settings (usually found via <code>Command + Shift + P</code> &gt; “Open MCP Settings”) and add the following:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"angular-cli"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@angular/cli"</span><span class="token punctuation">,</span> <span class="token string">"mcp"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p><strong>Note for VS Code users</strong>: The configuration file is typically located at:</p>
<ul>
<li><strong>macOS/Linux</strong>: <code>~/.vscode/mcp.json</code></li>
</ul>
</blockquote>
<blockquote>
<p><strong>Cursor users</strong>: You can add this JSON to your MCP configuration by opening the Command Palette (Cmd/Ctrl + Shift + P) and searching for “MCP.” The configuration file is located under the Tools &amp; MCP section.</p>
</blockquote>
<p>Once added, restart your editor and verify it works by asking: <em>“Generate a new Angular service called <code>api-client</code>.”</em></p>
<p><strong>Checkpoint:</strong> Your agent can now manage your Angular project. But how do we handle the UI design?</p>
<blockquote>
<p>Learn more about the basics of getting started with <a target="_blank" href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular">Angular and Cursor</a>.</p>
</blockquote>
<h2 id="kendo-ui-ai-coding-assistant-the-designer">Kendo UI AI Coding Assistant (The Designer)</h2>
<p>Building professional dashboards usually involves navigating documentation and manually wiring up complex components. The <strong>Kendo UI for Angular AI Coding Assistant</strong> changes this by acting as a local Kendo UI expert that understands the entire library.</p>
<p>The <a target="_blank" href="https://www.npmjs.com/package/@progress/kendo-angular-mcp">Kendo UI for Angular MCP Server</a> runs with <code>npx</code> and uses your Progress Telerik license directly.</p>
<p>First, you need a <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/installation#license-key-setup">valid Telerik license</a>. If you don’t have one, you can start a free trial and you don’t need a credit card. Second, you need to add the configuration to your <code>mcp.json</code> file:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"kendo-angular-mcp-server"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@progress/kendo-angular-mcp@latest"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"TELERIK_LICENSE"</span><span class="token punctuation">:</span> <span class="token string">"YOUR_LICENSE_KEY_HERE"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p><strong>Pro tip:</strong> If you have your license key set up globally on your machine, you can omit the <code>env</code> section!</p>
</blockquote>
<p>Now your agent has the tools to build a responsive orders dashboard. Instead of writing hundreds of lines of code, you can simply prompt your agent using the <code>#kendo_angular_assistant</code> handle:</p>
<blockquote>
<p><em>“Use the #kendo_angular_assistant to build an OrdersDashboardComponent. I need a responsive layout with a sidebar, and a Kendo Grid in the main content area showing ID, Customer, Date, Status and Total. Add a “New Order” button in a toolbar above the grid and use the Kendo Default theme.”</em></p>
</blockquote>
<p>The agent follows three steps. It analyzes your request to see which Kendo UI components you need. Then, it generates clean and typed code for TypeScript and HTML using Kendo UI standards. Finally, it implements the code in your files and helps you with the modules.</p>
<p>Need to iterate? Just ask for a refinement:</p>
<blockquote>
<p><em>“Awesome. Now update the grid to allow filtering by Status using a dropdown, and highlight ‘Pending’ orders in yellow.”</em></p>
</blockquote>
<p>The agent adapts the code instantly, following your specialized requirements.</p>
<h2 id="lets-see-it-in-action">Let’s See It in Action</h2>
<p>To start a new project, just run this command in your terminal:</p>
<pre class=" language-bash"><code class="prism  language-bash">ng new kendo-store
</code></pre>
<p>Now, configure your editor with both MCP servers. Here is a complete example of how your <code>mcp.json</code> should look. Don’t forget to add your Telerik license key:</p>
<pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
  <span class="token string">"servers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"angular-cli"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@angular/cli"</span><span class="token punctuation">,</span> <span class="token string">"mcp"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token string">"kendo-angular-mcp-server"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"stdio"</span><span class="token punctuation">,</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@progress/kendo-angular-mcp@latest"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        <span class="token string">"TELERIK_LICENSE"</span><span class="token punctuation">:</span> <span class="token string">"YOUR_LICENSE_KEY_HERE"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Now, let’s play with our Cursor agent. We want it to do the tasks for us using these new MCP tools.</p>
<p>For example, ask it which tools are available. It must show Kendo (if you have configured Angular or other MCP). Then, just use a prompt mentioning <code>#kendo_angular_assistant</code> like:</p>
<blockquote>
<p>#kendo_angular_assistant Create a basic Grid component that displays employee data with columns for ID, Name, Position, and Salary. Include sorting and pagination functionality.</p>
</blockquote>
<p>Let’s see how Cursor works with Kendo UI for Angular MCP:</p>
<p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-03/cursor-angular-kendo-mcp.gif?sfvrsn=cabfeb0c_2" alt="Searching Cursor: What tools have you available? And then selecting Kendo UI for Angular via MCP server"></p>
<p>Maybe you’re wondering, “Do I need to remember every prompt?” Don’t worry, Progress Kendo UI provides a list of <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/prompt-library">optimized prompts ready for use with the Kendo UI for Angular AI Coding Assistant</a>.</p>
<p>Now you are ready with prompts and MCP to give the agents the tools to work for you.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Honestly, we shouldn’t spend our time fighting with our tools. We need to make them work for us.</p>
<p>With <a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP</a> handling the CLI work and the <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo AI Assistant</a> building the professional UI, you can finally focus on what really matters: solving problems and building your app. No more boring boilerplate or searching documentation for hours.</p>
<p>Stop copying and pasting code from ChatGPT, or leaving your agent to work without tools. Give your agents the tools they need to work better for you!</p>
<ul>
<li><a target="_blank" href="https://angular.dev/ai/mcp">Angular MCP Documentation</a></li>
<li><a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/ai-tools/ai-assistant/getting-started">Kendo UI for Angular AI Coding Assistant</a></li>
</ul>
<p>And remember: Kendo UI for Angular comes with a free trial. So, give it a try if you aren’t already using it.</p>
<p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Try Kendo UI for Angular</a></p><img src="https://feeds.telerik.com/link/23055/17301664.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:bcaf5568-f230-4813-a975-4ad2d3fdfcf7</id>
    <title type="text">Guide to Creating an Angular-based Micro-frontend Application Using Native Federation</title>
    <summary type="text">Micro-frontends break a large frontend application into smaller, independent components. Here’s how to do this in Angular with Native Federation.</summary>
    <published>2026-03-10T20:09:00Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17297038/guide-creating-angular-based-micro-frontend-application-native-federation"/>
    <content type="text"><![CDATA[<p><span class="featured">Micro-frontends break a large frontend application into smaller, independent components. Follow these steps to create a micro-frontend in Angular with Native Federation.</span></p><p>Micro-frontends are an architectural pattern that extends the concept of microservices to frontend development. It involves breaking a large frontend application into smaller, independent and deployable components.</p><p>In this article, we will learn how to implement a micro-frontend architecture using Native Federation. We will:</p><ul><li>Create one host application</li><li>Create two remote client applications</li><li>Load the remote applications dynamically in the host application using routing or dynamic component loading</li></ul><p>Let&rsquo;s begin by creating the remote applications.</p><h2 id="creating-remote-apps">Creating Remote Apps</h2><p>We can use the Angular CLI to scaffold the client application. Let&rsquo;s create a remote app using the CLI command below.</p><pre><code>ng new remote-app1
</code></pre><p>After successfully creating the project, configure the Angular application as a remote app in the micro-frontend (MFE) setup by running the schematic command shown below.</p><pre><code>ng add @angular-architects/native-federation --project remote-app1 --port 4201 --type remote
</code></pre><p>Make sure to pass your project name after the <code>--project</code> flag (in this case, <code>remote-app1</code>). The CLI will then prompt you to confirm. After that, it will run the schematics and configure the Angular project as a remote application.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/native-federation-package-install.png?sfvrsn=dbf55db4_2" alt="The package @angular-architects/native-federation@21.0.3 will be installed and executed. Would you like to proceed? (y/n) screenshot" /></p><p>After the installation completes successfully, you will see a new federation.config.js file added to the project.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app2'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Component'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.ts'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Also, you will see changes in the angular.json file. Ideally, you should not change anything in this file except the <code>exposes</code> object. By default, it exposes the AppComponent, but you can also choose to expose routes if needed.</p><p>In the project, add home, product and invoice components. Then modify the route as shown below:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> routes<span class="token punctuation">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
        path<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
        component<span class="token punctuation">:</span> App<span class="token punctuation">,</span>
        children<span class="token punctuation">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Home1 <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'product'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Product <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">'invoice'</span><span class="token punctuation">,</span> component<span class="token punctuation">:</span> Invoice <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>On the AppComponent, add router-outlet and buttons to navigate as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Client App<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>home<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>product<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>invoice<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Invoice<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-outlet</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-outlet</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>After that, expose the route by updating the exposes section in federation.config.js, as shown below.</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app1'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Routes'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.routes'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In the same way, let&rsquo;s create one more remote application, but this time we won&rsquo;t add any routes to it. To create this application, run the following commands:</p><ul><li><code>ng new remote-app2</code></li><li><code>ng add @angular-architects/native-federation --project remote-app2 --port 4202 --type remote</code></li></ul><p>In this application, we will not configure any routes. This helps us understand how the host application can work with both an exposed <code>route</code> and an exposed <code>component</code>. So the federation.config.js of this application should look like:</p><pre class=" language-js"><code class="prism  language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> withNativeFederation<span class="token punctuation">,</span> shareAll <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@angular-architects/native-federation/config'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withNativeFederation</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'remote-app2'</span><span class="token punctuation">,</span>


  exposes<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">'./Component'</span><span class="token punctuation">:</span> <span class="token string">'./src/app/app.ts'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  shared<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token function">shareAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span> singleton<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> strictVersion<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> requiredVersion<span class="token punctuation">:</span> <span class="token string">'auto'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  skip<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token string">'rxjs/ajax'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/fetch'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/testing'</span><span class="token punctuation">,</span>
    <span class="token string">'rxjs/webSocket'</span><span class="token punctuation">,</span>
    <span class="token comment">// Add further packages you don't need at runtime</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  <span class="token comment">// Please read our FAQ about sharing libs:</span>
  <span class="token comment">// https://shorturl.at/jmzH0</span>

  features<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// New feature for more performance and avoiding</span>
    <span class="token comment">// issues with node libs. Comment this out to</span>
    <span class="token comment">// get the traditional behavior:</span>
    ignoreUnusedDeps<span class="token punctuation">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>So far, we have configured two client applications, and you should be able to run them independently on ports <strong>4201</strong> and <strong>4202</strong>. In this way, you can create any number of client applications and set up independent deployment pipelines for each of them.</p><h2>Creating Host App</h2><p>Let&rsquo;s create a host app using the Angular CLI command:</p><pre><code>ng new host-app 
</code></pre><p>After scaffolding the application, use the following schematic command to configure it as the host application.</p><pre><code>ng add @angular-architects/native-federation --project host-app --port 4200 --type dynamic-host
</code></pre><p>After the installation completes successfully:</p><ul><li>A new federation.config.js file is added to the project.</li><li>The federation.manifest.json file is added to the public folder.</li><li>The main.ts file is updated.</li><li>The angular.json file is updated.</li></ul><p>The updated main.ts should look like this:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> initFederation <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular-architects/native-federation'</span><span class="token punctuation">;</span>

<span class="token function">initFederation</span><span class="token punctuation">(</span><span class="token string">'federation.manifest.json'</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>_ <span class="token operator">=&gt;</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./bootstrap'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You can also see the corresponding changes reflected in the angular.json file build and serve section, as shown below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-json-file-build-serve.png?sfvrsn=b84fdaab_2" alt="angular.json file build and serve section" /></p><h2>Loading Remote Applications Dynamically</h2><p>Ideally, you should not make any changes to the scaffolded configuration, including the federation.config.ts file. The only file you need to update is federation.manifest.json, where you add the client application information.</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
    <span class="token string">"client1"</span><span class="token punctuation">:</span> <span class="token string">"http://localhost:4201/remoteEntry.json"</span><span class="token punctuation">,</span>
    <span class="token string">"client2"</span><span class="token punctuation">:</span> <span class="token string">"http://localhost:4202/remoteEntry.json"</span>
<span class="token punctuation">}</span>
</code></pre><p>Here, <code>client1</code> and <code>client2</code> correspond to the two remote applications. You can choose any names you like, but make sure to use the same names when configuring the routes in the host application.</p><p>In the host application, you can create routes corresponding to the remote apps as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">const</span> routes<span class="token punctuation">:</span> Routes <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
   path<span class="token punctuation">:</span><span class="token string">'home'</span><span class="token punctuation">,</span>
   component<span class="token punctuation">:</span>Home
<span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token punctuation">{</span>
    path<span class="token punctuation">:</span> <span class="token string">'client1'</span><span class="token punctuation">,</span>
    loadChildren<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client1'</span><span class="token punctuation">,</span> <span class="token string">'./Routes'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> m<span class="token punctuation">.</span>routes<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token punctuation">{</span>
    path<span class="token punctuation">:</span> <span class="token string">'client2'</span><span class="token punctuation">,</span>
    loadComponent<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
      <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client2'</span><span class="token punctuation">,</span> <span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>m<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> m<span class="token punctuation">.</span>App<span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span> path<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span> redirectTo<span class="token punctuation">:</span> <span class="token string">'home'</span><span class="token punctuation">,</span> pathMatch<span class="token punctuation">:</span> <span class="token string">'full'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>

<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><p>Next, add the router-outlet and the navigation links to move between the different remote applications, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>MFE APP<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/home<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Home<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/client1<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Client1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">routerLink</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/client2<span class="token punctuation">"</span></span> <span class="token attr-name">routerLinkActive</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>active<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Client2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-outlet</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-outlet</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Now, when you navigate to <code>client1</code>, the first remote application loads. Similarly, when you navigate to <code>client2</code>, the second remote application loads.</p><p>If you want to load applications side by side without navigating to different URLs, you can achieve this by using Angular&rsquo;s dynamic component loading feature.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">ViewChild</span><span class="token punctuation">(</span><span class="token string">'vcHostClient1'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> read<span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">,</span> <span class="token keyword">static</span><span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> vcHostClient1<span class="token operator">!</span><span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">;</span>

   @<span class="token function">ViewChild</span><span class="token punctuation">(</span><span class="token string">'vcHostClient2'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> read<span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">,</span> <span class="token keyword">static</span><span class="token punctuation">:</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> vcHostClient2<span class="token operator">!</span><span class="token punctuation">:</span> ViewContainerRef<span class="token punctuation">;</span>

  <span class="token keyword">async</span> <span class="token function">loadCient1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>

     <span class="token keyword">const</span> <span class="token punctuation">{</span>App<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client1'</span><span class="token punctuation">,</span><span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient1<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient1<span class="token punctuation">.</span><span class="token function">createComponent</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">async</span> <span class="token function">loadClient2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span>App<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">loadRemoteModule</span><span class="token punctuation">(</span><span class="token string">'client2'</span><span class="token punctuation">,</span><span class="token string">'./Component'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient2<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vcHostClient2<span class="token punctuation">.</span><span class="token function">createComponent</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>And on the template, create ng-template to load as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadCient1()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Client 1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>loadClient2()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Load Client 2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ng-template</span> <span class="token attr-name">#vcHostClient1</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ng-template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ng-template</span> <span class="token attr-name">#vcHostClient2</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ng-template</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>So that's how you can load remote apps in different ways.</p><h2 id="summary">Summary</h2><p>In this article, we learned step by step how to build a micro-frontend application using Native Federation. I hope you found it helpful&mdash;thanks for reading!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">How to Use Cursor with Modern Angular</h4></div><div class="col-8"><p class="u-fs16 u-mb0">This practical guide teaches you <a target="_blank" href="https://www.telerik.com/blogs/how-to-use-cursor-modern-angular">how to set up Cursor in Angular 21</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17297038.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:32eb8035-5d74-437b-8c1a-6915601b6b8e</id>
    <title type="text">Singleton or Not? Understanding Angular Services the Right Way</title>
    <summary type="text">Angular services are singleton and tree-shakeable by default, but there are some important catches to these states. Let’s understand what those are.</summary>
    <published>2026-03-02T18:06:24Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17287999/singleton-not-understanding-angular-services-right-way"/>
    <content type="text"><![CDATA[<p><span class="featured">Angular services are singleton and tree-shakeable by default, but there are some important catches to these states. Let&rsquo;s understand what those are.</span></p><p>Angular services are a core feature of the framework, used to share data and functionality across components. Their primary purposes include:</p><ul><li>Angular services are classes used to organize and share reusable logic across components.</li><li>They help keep components clean by handling data, business rules and API interactions.</li><li>Services use Angular&rsquo;s dependency injection system, making them easy to share and test.</li><li>They can also act as lightweight state stores using signals, computed values and effects.</li></ul><p>You create an Angular service by running a CLI command:</p><pre><code>ng g s log
</code></pre><p>This command should scaffold the <code>LogService</code> as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Log</span> <span class="token punctuation">{</span>
  
<span class="token punctuation">}</span>
</code></pre><p>When you create a service in Angular, you encounter two key characteristics:</p><ol><li>Services are tree-shakeable</li><li>Services are singletons</li></ol><p>In this article, we will explore the truthfulness of these two behaviors in depth. Read on.</p><h2 id="are-angular-services-tree-shakeable">Are Angular Services Tree-Shakeable?</h2><p>By default, Angular services are tree-shakeable. Tree-shaking is a dead code elimination technique that removes unused code from the final bundle, reducing application size and improving performance.</p><p>Angular tree-shakes a service and excludes it from the final bundle:</p><ol><li>If it is provided with <code>providedIn</code> option</li><li>If it is not re-provided anywhere in the application using <code>providers</code> array</li><li>If it is not used anywhere in the application</li></ol><p>Let&rsquo;s consider the service below. We are just logging a message in the service file.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'service is part of the bundle'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Log</span> <span class="token punctuation">{</span>

<span class="token punctuation">}</span>
</code></pre><p>Let&rsquo;s assume that this service is not used anywhere in the application, and you run the Angular application. In the browser console, you won&rsquo;t find the message logged.</p><p>Next, in the AppComponent (the root component of the application) or any other component, add the <code>LogService</code> to the <code>providers</code> array, as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./app.html'</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span><span class="token punctuation">[</span>Log<span class="token punctuation">]</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./app.css'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
 
<span class="token punctuation">}</span>
</code></pre><p>Even in this case, the service isn&rsquo;t being used anywhere in the application. However, you can still see its messages logged in the browser. This happens because when a service is added to the providers array of any component, it is no longer tree-shakeable. As a result, Angular includes it in the final output bundle, even if it&rsquo;s never actually used in the application.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-services-providedin-providers.png?sfvrsn=a234ba6_2" alt="Different ways of providing Angular services. providedIn – tree-shakeable service – means that if not used in app, it will not be part of the final output bundle. Providers – A non-tree-shakeable service means that, even if unused in the app, it will be part of the final output bundle" /></p><p>The takeaway is that a service provided with <code>providedIn</code> is tree-shakeable, but a service provided in a component&rsquo;s <code>providers</code> array is not tree-shakeable.</p><h2 id="are-services-singletons">Are Services Singletons?</h2><p>By default, Angular Services are singletons. This means that if you do not re-provide them, Angular creates only one object of the service. To understand this, let&rsquo;s modify the service as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Log</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> <span class="token keyword">static</span> instanceCount <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span>instanceCount<span class="token operator">++</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Log service instance count: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Log<span class="token punctuation">.</span>instanceCount<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><p>We add a static variable to count the number of instances Angular creates for this service. And, in the constructor, we increment it to track the number of objects.</p><p>Next, we use the <code>LogService</code> in two or more different components. To do that, we simply inject the service as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child2'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./child2.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./child2.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child2</span> <span class="token punctuation">{</span>

  logService  <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>And in other components as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child1'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./child1.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./child1.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child1</span> <span class="token punctuation">{</span>

  logService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>So, even though the <code>LogService</code> is injected into two components, Angular still creates only one instance of it. In the browser console, you should see the following output.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/console-one-instance.png?sfvrsn=e25d2dc5_2" alt="Console: service is part of the bundle. Log service instance count: 1. Angular is running in development mode." /></p><p>Now, let&rsquo;s go ahead and re-provide the service again in the <code>Child2Component</code>.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child2'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./child2.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./child2.css'</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span><span class="token punctuation">[</span>Log<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child2</span> <span class="token punctuation">{</span>

  log <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>You will observe that two objects have been created in the service.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/console-two-instances.png?sfvrsn=858b686a_2" alt="Console: Log service instance count: 1. Log service instance count: 2." /></p><p>By default, an Angular service is a singleton, but if it is provided again in a component&rsquo;s <code>providers</code> array, Angular creates additional instances.</p><p>Please be informed that even if a service is provided in five different components, Angular does not necessarily create five separate instances. The actual number of instances depends on the provider hierarchy.</p><p>Let&rsquo;s understand the above statement with an example. We have created a service as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Log</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> <span class="token keyword">static</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    Log<span class="token punctuation">.</span>count <span class="token operator">=</span> Log<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Log service instance count: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Log<span class="token punctuation">.</span>count<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>counter <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>counter <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">getCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>counter<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The <code>LogService</code> is used on the <code>child1</code> component:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Log <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../log'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> template <span class="token operator">=</span> <span class="token template-string"><span class="token string">`
&lt;p&gt;Child 1 Count = {{log.getCount()}}&lt;/p&gt;
&lt;button (click)="update()"&gt;Update Count &lt;/button&gt;
`</span></span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child1'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> template<span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child1</span> <span class="token punctuation">{</span>

  log <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><p>Next, it is used on the <code>Child2</code> component:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Log <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../log'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> template <span class="token operator">=</span> <span class="token template-string"><span class="token string">`
&lt;p&gt;Child 2 Count = {{log.getCount()}}&lt;/p&gt;
&lt;button (click)="update()"&gt;Update Count &lt;/button&gt;
`</span></span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child2'</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> template<span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child2</span> <span class="token punctuation">{</span>

  log <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Both of these components are used in the App Component:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Child1 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./child1/child1'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Child2 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./child2/child2'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> template <span class="token operator">=</span><span class="token template-string"><span class="token string">` &lt;h1&gt;App Component&lt;/h1&gt;
&lt;app-child1&gt;&lt;/app-child1&gt;
&lt;app-child2&gt;&lt;/app-child2&gt;
`</span></span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>Child1<span class="token punctuation">,</span>Child2<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> template<span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>

<span class="token punctuation">}</span>
</code></pre><p>Now, when you run the application, you can see that data is passed between the <code>Child1</code> and <code>Child2</code> components, and Angular creates only one instance of the <code>LogService</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-child-count-one-log-service.png?sfvrsn=ed5d88ea_2" alt="Angular app component with Child 1 count = 12 and a button to update child count. Then Child 2 count = 12, with another update count button. Console shows one log service instance." /></p><p>Next, let&rsquo;s make a small change and add <code>LogService</code> to the <code>providers</code> array of the Child2 component.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-child2'</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> template<span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>Log<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Child2</span> <span class="token punctuation">{</span>

  log <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Log<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>log<span class="token punctuation">.</span><span class="token function">setCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Now, what do you notice in the output? You should see the following:</p><ol><li>Two separate instances of <code>LogService</code> are created.</li><li>Data is no longer shared between the Child1 and Child2 components.</li></ol><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-child-count-two-log-service-instances.png?sfvrsn=fd43e670_1" alt="Angular app component with Child 1 count = 6 and a button to update child count. Then Child 2 count = 0, with another update count button. Console shows two log service instances." /></p><p>Next, let&rsquo;s make another small change and add <code>LogService</code> to the <code>providers</code> array of the App Component.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Child1 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./child1/child1'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Child2 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./child2/child2'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Log <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./log'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> template <span class="token operator">=</span> <span class="token template-string"><span class="token string">` &lt;h1&gt;App Component&lt;/h1&gt;
&lt;app-child1&gt;&lt;/app-child1&gt;
&lt;app-child2&gt;&lt;/app-child2&gt;
`</span></span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>Child1<span class="token punctuation">,</span> Child2<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> template<span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>Log<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>

<span class="token punctuation">}</span>
</code></pre><p>Now, what do you observe in the output? Data is still not shared between the Child1 and Child2 components, and only two instances of <code>LogService</code> are created.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-two-log-service-instances-not-three.png?sfvrsn=d82e452c_2" alt="Angular app component with Child 1 count = 5 and a button to update child count. Then Child 2 count = 3, with another update count button. Console shows two log service instances." /></p><p>Two instances of <code>LogService</code> are created, not three. You might wonder why it is not three, even though <code>LogService</code> is provided in multiple places:</p><ol><li>The Child1 Component</li><li>The App Component</li><li>And using the providedIn option in the service itself</li></ol><p>Let&rsquo;s understand the above behavior. Angular works with a service in the following steps:</p><ul><li><strong>Step 1</strong> &ndash; Is the service used?</li><li><strong>Step 2</strong> &ndash; Is the service injected?</li><li><strong>Step 3</strong> &ndash; Is the service provided?</li></ul><p>So, from the above steps, if a service is used but not injected, Step 2 fails. And for that, Angular gives a compilation error. It searches for the injection in the same component.</p><p>However, whether a service is actually provided is determined by Angular at runtime. So, if a service is used and injected but not provided, Angular throws a runtime error, which looks something like this:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-runtime-error.png?sfvrsn=d2e17299_2" alt="Angular runtime error in Console" /></p><p>Angular searches for a service provider in the component tree hierarchy. It first looks in the current component; if it finds a provider there, it uses that instance. If not, it moves up to the parent component and continues searching.</p><p>If no provider is found in the hierarchy, Angular finally uses the provider configuration defined in the service itself. If it still doesn&rsquo;t find a provider configuration in the service, Angular throws a runtime error like the one shown above.</p><p>Let&rsquo;s apply the above explanation to the Child2 component.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/log-service-hierarchy-1.png?sfvrsn=6f375482_2" alt="Step 1 at this.log.setCount. Step 2 above, at log = inject(Log). Step 3 above, at providers: [Log]." /></p><p>For the Child2 component, since Angular finds the LogService provided directly in the component, it uses the instance created there and does not continue searching in parent components or in the service&rsquo;s own provider configuration.</p><p>However, for the Child1 component, Angular does not find LogService provided within the component itself, so it moves up to the parent AppComponent and finds it there. It then uses that instance and does not continue searching in the service&rsquo;s own provider configuration.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/log-service-hierarchy-2.png?sfvrsn=11117e6b_2" alt="Step 1 at this.log.setCount. Step 2 above, at log = inject(Log). Step 3 above, at providers: [Log]." /></p><p>Now you can see that the Child1 and Child2 components use different instances of LogService, which is why they cannot share data between them.</p><p>Also, because LogService is used in only two places, Angular creates one instance for the Child2 component (since it is provided there) and another instance for the Child1 component (from the AppComponent). Angular never reaches the service&rsquo;s own provider configuration to create an additional instance.</p><p>This is why only two instances of LogService are created, not three.</p><h2 id="summary">Summary</h2><p>We learned in this article that Angular services are singleton by default, but when a service is re-provided, Angular creates additional instances.</p><p>We also saw that, when using services to share data in a large application, we must be careful. If a service is accidentally re-provided, it may behave unexpectedly and fail to share data as intended.</p><p>Additionally, a service is tree-shakeable by default, but once it is added to a providers array, it is no longer tree-shakeable.</p><p>I hope you found this article useful. Thanks for reading!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">A Practical Guide for State Management Using Angular Services and Signals</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Learn how <a target="_blank" href="https://www.telerik.com/blogs/practical-guide-state-management-using-angular-services-signals">Angular Services with Signals</a> can simplify your application architecture and handle state management.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17287999.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9b9db956-7722-4162-83a2-cf5d70fe74e3</id>
    <title type="text">How to Use Cursor with Modern Angular</title>
    <summary type="text">This practical guide teaches you how to set up Cursor in Angular 21.</summary>
    <published>2026-02-23T18:07:49Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17282288/how-to-use-cursor-modern-angular"/>
    <content type="text"><![CDATA[<p><span class="featured">This practical guide teaches you how to set up Cursor in Angular 21.</span></p><p>In this article, you will learn how to set up Cursor for a modern Angular project (for example, version 21.0) and how to use it in a practical way. We will cover basic setup, useful features and simple examples that you can try right away.</p><p>If you are starting a new project with Angular 20 or later, make sure to configure Cursor rules upfront to work with Cursor more effectively.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-rules-angular.png?sfvrsn=c834aa54_2" alt="Cursor – http://docs.cursor.com/en/context/rules" /></p><p>After successfully executing the command, you&rsquo;ll notice that along with the scaffolded Angular project, the Angular CLI also adds a cursor.mdc rule file to the project.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-mdc.png?sfvrsn=6ee612ef_2" alt="cursor.mdc in product-app - .cursor/rules" /></p><p>You can modify the generated rule file to suit your project requirements. Feel free to customize the Cursor rules as needed. For example, as shown below, I have specified the Angular version to be used by the agents.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-use-angular-21.png?sfvrsn=95528c46_2" alt="Cursor rules told to use Angular version 21.0" /></p><p>If you are working with an existing project, you can manually add the Cursor rules file to the project. Make sure to add the rule in the root of the project inside .cursor/rules. You can also go to <strong>Cursor-&gt; Settings -&gt; Cursor Setting -&gt; Rules, Skills, Subagents</strong> to add a rule using the IDE.</p><p>Cursor automatically detects rules from <strong>.cursor/rules/cursor.mdc</strong> or <strong>.cursor/rules.md</strong>. When using Angular CLI, a cursor.mdc file is already added, so do not add rules.md. You should have only one of these files in the project.</p><p>Also, verify that <code>alwaysApply: true</code> is set in the rule file. Alternatively, you can manually add the following line at the top of the cursor.mdc file.</p><pre><code>alwaysApply: true
</code></pre><p>You may also enable this setting by selecting the option from the dropdown at the top of the file in the Cursor IDE, as shown in the image below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-rules-manual-always-apply.png?sfvrsn=a07d9fcf_2" alt="cursor.mdc rules – apply manually dropdown set to always apply" /></p><p>Always make sure to configure project rules to:</p><ul><li>Apply domain-specific knowledge to the codebase</li><li>Set the version to be used</li><li>Select architecture decisions regarding whether to use signals or RxJS</li><li>Use a specific coding style</li></ul><p>To validate whether the rule is applied to your project or not, open the chat in ask mode and ask which version you are using as shown image below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-chat-angular-version.png?sfvrsn=ec63511_2" alt="cursor.mdc chat ask – Which version of Angular are you going to work with? From rules, Angular 21" /></p><p>Next, make sure to connect to the Angular MCP server. To do that on the terminal run the command:</p><pre><code>ng mcp
</code></pre><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-cli-mcp-server-configuration.png?sfvrsn=da8a6255_2" alt="To start using the Angular CLI MCP Server, add this configuration to your host…" /></p><p>Next, in the Cursor IDE, go to <strong>Cursor-&gt; Settings -&gt; Cursor Setting -&gt; Tools and MCP</strong> to add a custom MCP.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-ide-custom-mcp.png?sfvrsn=c556e6bd_2" alt="Cursor IDE - Settings - Tools and MCP: add a custom MCP." /></p><p>Paste the configuration created by the <code>ng mcp</code> command.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token punctuation">{</span>
  <span class="token string">"mcpServers"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token string">"angular-cli"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token string">"command"</span><span class="token punctuation">:</span> <span class="token string">"npx"</span><span class="token punctuation">,</span>
      <span class="token string">"args"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"-y"</span><span class="token punctuation">,</span> <span class="token string">"@angular/cli"</span><span class="token punctuation">,</span> <span class="token string">"mcp"</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>After adding the Angular MCP server, you can validate the setup by asking Cursor to list all the MCP servers it is using, and it should list the Angular MCP server as shown in the image below.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-ask-which-mcp.png?sfvrsn=c61ebb88_2" alt="Can you tell me which MCP you are going to use? 1. Web fetch – mcp_web_fetch; 2. MCP resources – list_mcp_resources, fetch_mcp_resource; 3. Angular CLI MCP – mcp_angular-cli_ai_tutor" /></p><p>After setting up these elements, open the Agent pane and we&rsquo;ll create a plan to implement the login screen in Angular.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-angular-create-login-screen.png?sfvrsn=d1ff018c_2" alt="Angular Cursor chat prompt: Give me a plan to Create a login component. Component should use latest form signal instead of reactive or template forms. Login will have email and password field. Try to keep implementation as simple as possible." /></p><p>As shown in the image above, I have selected <strong>Plan Mode</strong> and am asking very specific questions. I am clear on what I want to implement, which features I want to use and which I do not.</p><p>Cursor created a plan that closely matches what I wanted, and I am satisfied with it. As shown in the image below, it uses the latest form functions to create a signal-based form and also indicates that it used the Angular MCP server to do this.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/angular-cursor-component-design-simple.png?sfvrsn=d6b879a5_2" alt="Angular login plan in Cursor with heading Component Design (simple) includes list of model, form, imports, decorator, template" /></p><p>Next, click the <strong>Build</strong> button. The cursor will switch to <strong>Agent mode</strong>, and the Login feature will be built according to the plan. Once the cursor finishes creating the code, click <strong>Review</strong> to begin reviewing the generated code.</p><p>After review, click either <strong>Keep All</strong> or <strong>Commit</strong> to commit the code to the project.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-commit.png?sfvrsn=8497ecc4_2" alt="Add login route and link to app, with Commit button, 6 files selected" /></p><p>If you are on the main branch, it may ask you whether you want to create a new branch or commit to the main branch.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-02/cursor-commit-main-new.png?sfvrsn=b8a3ca1c_2" alt="Commit on Main Branch – buttons to Commit on Main or Create New Branch" /></p><p>After completing this setup, Cursor generated the LoginComponent, which uses the latest Signal Forms, and I am very happy with the result.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">LoginComponent</span> <span class="token punctuation">{</span>
  <span class="token keyword">protected</span> readonly loginModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>LoginData<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    email<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
    password<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">protected</span> readonly loginForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginModel<span class="token punctuation">,</span> <span class="token punctuation">(</span>path<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">required</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Email is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">email</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span>email<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Enter a valid email address'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">required</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span>password<span class="token punctuation">,</span> <span class="token punctuation">{</span> message<span class="token punctuation">:</span> <span class="token string">'Password is required'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">protected</span> <span class="token function">onSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> Event<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>loginForm<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> credentials <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">loginModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Logging in with:'</span><span class="token punctuation">,</span> credentials<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The generated code is based on Angular 21.0 features and adheres to project-specific rules defined in the Angular MCP Server. As your project grows, you can add more rules at different levels, but this guide should be enough to help you get started.</p><p>I hope you find this article useful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular 21: My Favorite New Features, a Quick Demo and a Look at What&rsquo;s Next</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See what else you may have missed that is <a target="_blank" href="https://www.telerik.com/blogs/angular-21-my-favorite-new-features-quick-demo-look-whats-next">new in Angular 21</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17282288.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:4cbed3c2-c291-4f35-b0c6-d2889ec9cd89</id>
    <title type="text">Ultimate Angular Firebase Setup with AnalogJS</title>
    <summary type="text">Streamline your Angular setup with this build! Using Angular 20+, signals, AnalogJS, pure Firebase, Firestore Lite and clean injection tokens, we can get rolling with ease.</summary>
    <published>2026-02-17T16:33:38Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17277992/ultimate-angular-firebase-setup-analogjs"/>
    <content type="text"><![CDATA[<p><span class="featured">Streamline your Angular setup with this build! Using Angular 20+, signals, AnalogJS, pure Firebase, Firestore Lite and clean injection tokens, we can get rolling with ease.</span></p><p>Angular has changed a lot in the last few years. We now are at Version 20. We can simplify the Angular setup with Firebase, and only add the minimum necessary packages and server infrastructure to get our app working in any environment.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/screenshot_2025-10-21_202140.png?sfvrsn=b0a95f62_2" alt="Screenshot 2025-10-21 202140.png" /></p><h2 id="tldr">TL;DR</h2><p>This app setup takes the best of Firebase setups to cover all your bases. You can fetch data purely on the server for good SEO, validate the schema meta data and have a safe &ldquo;login wall&rdquo; to prevent unauthorized user access on the client. No need for cookies, sessions or authorization on the server.</p><h2 id="remove-zonejs">Remove ZoneJS</h2><p>We do NOT need ZoneJS anymore. Signals make Angular faster and more responsive, and remove unnecessary bloat.</p><h2 id="analogjs">AnalogJS</h2><p>Generate a new <a target="_blank" href="https://analogjs.org/docs/getting-started">Analog component</a>, or use an existing one.</p><h3 id="app.config.ts">app.config.ts</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> {
  provideHttpClient<span class="token punctuation">,</span>
  withFetch<span class="token punctuation">,</span>
  withInterceptors<span class="token punctuation">,</span>
} <span class="token keyword">from</span> <span class="token string">'@angular/common/http'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> {
  ApplicationConfig<span class="token punctuation">,</span>
  provideBrowserGlobalErrorListeners<span class="token punctuation">,</span>
  provideZonelessChangeDetection
} <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { provideClientHydration<span class="token punctuation">,</span> withEventReplay } <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { provideFileRouter<span class="token punctuation">,</span> requestContextInterceptor } <span class="token keyword">from</span> <span class="token string">'@analogjs/router'</span><span class="token punctuation">;</span>

export const appConfig: ApplicationConfig <span class="token operator">=</span> {
  providers: <span class="token punctuation">[</span>
    provideBrowserGlobalErrorListeners<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    provideZonelessChangeDetection<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// &lt;----- change</span>
    provideFileRouter<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    provideHttpClient<span class="token punctuation">(</span>
      withFetch<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      withInterceptors<span class="token punctuation">(</span><span class="token punctuation">[</span>requestContextInterceptor<span class="token punctuation">]</span><span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
    provideClientHydration<span class="token punctuation">(</span>withEventReplay<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
}<span class="token punctuation">;</span>
</code></pre><p>Here we change out the <code>Zone</code> provider for a <code>Zoneless</code> one.</p><pre class=" language-sql"><code class="prism  language-sql">npm uninstall zone<span class="token punctuation">.</span>js
</code></pre><p>Also, remove any imports in the <code>main.server.ts</code> and in <code>main.ts</code>.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token comment">// Remove these lines</span>
<span class="token keyword">import</span> <span class="token string">'zone.js/node'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token string">'zone.js'</span><span class="token punctuation">;</span>
</code></pre><h3 id="vite.config.ts">vite.config.ts</h3><p>I also added an alias for <code>@lib</code>, <code>services</code> and <code>@components</code>. I changed the default public prefix for <code>.env</code> info from <code>VITE_</code> to <code>PUBLIC_</code>, but this is optional. Feel free to change the <code>preset</code> to where you want to deploy.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token comment">/// &lt;reference types="vitest" /&gt;</span>

<span class="token keyword">import</span> { defineConfig } <span class="token keyword">from</span> <span class="token string">'vite'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> analog <span class="token keyword">from</span> <span class="token string">'@analogjs/platform'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> tailwindcss <span class="token keyword">from</span> <span class="token string">'@tailwindcss/vite'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { resolve } <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>

<span class="token comment">// https://vitejs.dev/config/</span>
export <span class="token keyword">default</span> defineConfig<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>{
  build: {
    target: <span class="token punctuation">[</span><span class="token string">'es2020'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  }<span class="token punctuation">,</span>
  envPrefix: <span class="token punctuation">[</span><span class="token string">'PUBLIC_'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  resolve: {
    alias: {
      <span class="token string">'@services'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/services'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token string">'@components'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/components'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token string">'@lib'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/lib'</span><span class="token punctuation">)</span>
    }<span class="token punctuation">,</span>
    mainFields: <span class="token punctuation">[</span><span class="token string">'module'</span><span class="token punctuation">]</span>
  }<span class="token punctuation">,</span>
  plugins: <span class="token punctuation">[</span>
    analog<span class="token punctuation">(</span>{
      ssr: <span class="token boolean">true</span><span class="token punctuation">,</span>
      static: <span class="token boolean">false</span><span class="token punctuation">,</span>
      nitro: {
        alias: {
          <span class="token string">'@lib'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/lib'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token string">'@services'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/services'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token string">'@components'</span>: resolve<span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'./src/app/components'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        }<span class="token punctuation">,</span>
        preset: <span class="token string">'vercel-edge'</span>
      }<span class="token punctuation">,</span>
      prerender: {
        routes: <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      }<span class="token punctuation">,</span>
    }<span class="token punctuation">)</span><span class="token punctuation">,</span>
    tailwindcss<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
}<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="utility-functions">Utility Functions</h3><p>For many apps I use in Angular, I have created a few reusable utility functions.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { TransferState<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> makeStateKey } <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ActivatedRoute } <span class="token keyword">from</span> <span class="token string">"@angular/router"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { map } <span class="token keyword">from</span> <span class="token string">"rxjs"</span><span class="token punctuation">;</span>

export const useAsyncTransferState <span class="token operator">=</span> async <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    name: string<span class="token punctuation">,</span>
    fn: <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> T
<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {
    const state <span class="token operator">=</span> inject<span class="token punctuation">(</span>TransferState<span class="token punctuation">)</span><span class="token punctuation">;</span>
    const <span class="token keyword">key</span> <span class="token operator">=</span> makeStateKey<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
    const cache <span class="token operator">=</span> state<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token keyword">key</span><span class="token punctuation">,</span> <span class="token boolean">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>cache<span class="token punctuation">)</span> {
        <span class="token keyword">return</span> cache<span class="token punctuation">;</span>
    }
    const <span class="token keyword">data</span> <span class="token operator">=</span> await fn<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> T<span class="token punctuation">;</span>
    state<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">key</span><span class="token punctuation">,</span> <span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">data</span><span class="token punctuation">;</span>
}<span class="token punctuation">;</span>

export const useTransferState <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    name: string<span class="token punctuation">,</span>
    fn: <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> T
<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {
    const state <span class="token operator">=</span> inject<span class="token punctuation">(</span>TransferState<span class="token punctuation">)</span><span class="token punctuation">;</span>
    const <span class="token keyword">key</span> <span class="token operator">=</span> makeStateKey<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
    const cache <span class="token operator">=</span> state<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token keyword">key</span><span class="token punctuation">,</span> <span class="token boolean">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>cache<span class="token punctuation">)</span> {
        <span class="token keyword">return</span> cache<span class="token punctuation">;</span>
    }
    const <span class="token keyword">data</span> <span class="token operator">=</span> fn<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> T<span class="token punctuation">;</span>
    state<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">key</span><span class="token punctuation">,</span> <span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">data</span><span class="token punctuation">;</span>
}<span class="token punctuation">;</span>

export const injectResolver <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>name: string<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
    inject<span class="token punctuation">(</span>ActivatedRoute<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">data</span><span class="token punctuation">.</span>pipe<span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>map<span class="token punctuation">(</span>r <span class="token operator">=</span><span class="token operator">&gt;</span> r<span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

export const injectSnapResolver <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>name: string<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span>
    inject<span class="token punctuation">(</span>ActivatedRoute<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">snapshot</span><span class="token punctuation">.</span><span class="token keyword">data</span><span class="token punctuation">[</span>name<span class="token punctuation">]</span> <span class="token keyword">as</span> T<span class="token punctuation">;</span>
</code></pre><ul><li><code>useAsyncTransferState</code> &ndash; This allows the data to be fetched on the server once and hydrated to the browser. By default, the server would fetch the data, then the client would refetch the data. We don&rsquo;t want extraneous reads in Firestore.</li><li><code>injectResolver</code> and <code>injectSnapResolver</code> are helpers to add the resolver data to your component.</li></ul><h3 id="schema.service.ts">schema.service.ts</h3><p>By default, you can inject <code>Meta</code> to add meta data. However, there is no default schema tool. I created a basic one.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Injectable<span class="token punctuation">,</span> Inject } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { DOCUMENT } <span class="token keyword">from</span> <span class="token string">'@angular/common'</span><span class="token punctuation">;</span>

<span class="token variable">@Injectable</span><span class="token punctuation">(</span>{ providedIn: <span class="token string">'root'</span> }<span class="token punctuation">)</span>
export class <span class="token keyword">Schema</span> {
    constructor<span class="token punctuation">(</span><span class="token variable">@Inject</span><span class="token punctuation">(</span>DOCUMENT<span class="token punctuation">)</span> private document: Document<span class="token punctuation">)</span> { }

    <span class="token comment">/**
     * Adds or updates a JSON-LD script tag in &lt;head&gt;, similar to Title/Meta.
     */</span>
    setSchema<span class="token punctuation">(</span><span class="token keyword">data</span>: Record<span class="token operator">&lt;</span>string<span class="token punctuation">,</span> unknown<span class="token operator">&gt;</span><span class="token punctuation">,</span> id <span class="token operator">=</span> <span class="token string">'jsonld-schema'</span><span class="token punctuation">)</span>: void {
        const json <span class="token operator">=</span> JSON<span class="token punctuation">.</span>stringify<span class="token punctuation">(</span><span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">.</span>replace<span class="token punctuation">(</span><span class="token operator">/</span><span class="token operator">&lt;</span><span class="token operator">/</span>g<span class="token punctuation">,</span> <span class="token string">'\\u003c'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Avoid duplicates</span>
        let script <span class="token operator">=</span> this<span class="token punctuation">.</span>document<span class="token punctuation">.</span>head<span class="token punctuation">.</span>querySelector<span class="token operator">&lt;</span>HTMLScriptElement<span class="token operator">&gt;</span><span class="token punctuation">(</span>
            <span class="token punctuation">`</span>script<span class="token comment">#${id}[type="application/ld+json"]`</span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>script<span class="token punctuation">)</span> {
            script <span class="token operator">=</span> this<span class="token punctuation">.</span>document<span class="token punctuation">.</span>createElement<span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            script<span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span>
            script<span class="token punctuation">.</span><span class="token keyword">type</span> <span class="token operator">=</span> <span class="token string">'application/ld+json'</span><span class="token punctuation">;</span>
            this<span class="token punctuation">.</span>document<span class="token punctuation">.</span>head<span class="token punctuation">.</span>appendChild<span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span>
        }

        script<span class="token punctuation">.</span>textContent <span class="token operator">=</span> json<span class="token punctuation">;</span>
    }

    <span class="token comment">/** Optional cleanup */</span>
    removeSchema<span class="token punctuation">(</span>id <span class="token operator">=</span> <span class="token string">'jsonld-schema'</span><span class="token punctuation">)</span>: void {
        const existing <span class="token operator">=</span> this<span class="token punctuation">.</span>document<span class="token punctuation">.</span>getElementById<span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>existing<span class="token punctuation">)</span> {
            this<span class="token punctuation">.</span>document<span class="token punctuation">.</span>head<span class="token punctuation">.</span>removeChild<span class="token punctuation">(</span>existing<span class="token punctuation">)</span><span class="token punctuation">;</span>
        }
    }
}
</code></pre><h2 id="firebase">Firebase</h2><p>Next, install pure Firebase. <strong>DO NOT</strong> use <code>@angular/fire</code>, as it is built with ZoneJS in mind.</p><pre class=" language-sql"><code class="prism  language-sql">npm i firebase
</code></pre><h3 id="env">ENV</h3><p>Set up your <code>.env</code> file to have your firebase public API key available.</p><pre class=" language-sql"><code class="prism  language-sql">PUBLIC_FIREBASE_CONFIG<span class="token operator">=</span>{<span class="token string">"apiKey"</span>:<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token string">"authDomain"</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>}
</code></pre><p>Next, create the Firebase Service file which will have your firebase sharing injection tokens.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { isPlatformBrowser } <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { inject<span class="token punctuation">,</span> InjectionToken<span class="token punctuation">,</span> PLATFORM_ID } <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { FirebaseApp<span class="token punctuation">,</span> getApp<span class="token punctuation">,</span> getApps<span class="token punctuation">,</span> initializeApp } <span class="token keyword">from</span> <span class="token string">"firebase/app"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { Auth<span class="token punctuation">,</span> getAuth } <span class="token keyword">from</span> <span class="token string">"firebase/auth"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { doc<span class="token punctuation">,</span> Firestore<span class="token punctuation">,</span> getDoc<span class="token punctuation">,</span> getFirestore } <span class="token keyword">from</span> <span class="token string">"firebase/firestore"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> {
    getFirestore <span class="token keyword">as</span> getFirestoreLite<span class="token punctuation">,</span>
    getDoc <span class="token keyword">as</span> getDocLite<span class="token punctuation">,</span>
    doc <span class="token keyword">as</span> docLite
} <span class="token keyword">from</span> <span class="token string">'firebase/firestore/lite'</span>

const firebase_config <span class="token operator">=</span> JSON<span class="token punctuation">.</span>parse<span class="token punctuation">(</span><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>env<span class="token punctuation">[</span><span class="token string">'PUBLIC_FIREBASE_CONFIG'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

export const FIREBASE_APP <span class="token operator">=</span> new InjectionToken<span class="token operator">&lt;</span>FirebaseApp<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    <span class="token string">'firebase-app'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            <span class="token keyword">return</span> getApps<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length
                ? getApp<span class="token punctuation">(</span><span class="token punctuation">)</span>
                : initializeApp<span class="token punctuation">(</span>firebase_config<span class="token punctuation">)</span><span class="token punctuation">;</span>

        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>

export const FIREBASE_AUTH <span class="token operator">=</span> new InjectionToken<span class="token operator">&lt;</span>Auth <span class="token operator">|</span> <span class="token boolean">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>
    <span class="token string">'firebase-auth'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            const platformID <span class="token operator">=</span> inject<span class="token punctuation">(</span>PLATFORM_ID<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>isPlatformBrowser<span class="token punctuation">(</span>platformID<span class="token punctuation">)</span><span class="token punctuation">)</span> {
                const app <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_APP<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> getAuth<span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span>
            }
            <span class="token keyword">return</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>

export const FIREBASE_FIRESTORE <span class="token operator">=</span> new InjectionToken<span class="token operator">&lt;</span>Firestore<span class="token operator">&gt;</span><span class="token punctuation">(</span>
    <span class="token string">'firebase-firestore'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            const platformID <span class="token operator">=</span> inject<span class="token punctuation">(</span>PLATFORM_ID<span class="token punctuation">)</span><span class="token punctuation">;</span>
            const app <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_APP<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>isPlatformBrowser<span class="token punctuation">(</span>platformID<span class="token punctuation">)</span><span class="token punctuation">)</span> {
                <span class="token keyword">return</span> getFirestore<span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span>
            }
            <span class="token keyword">return</span> getFirestoreLite<span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token punctuation">;</span>
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>

export const FIRESTORE_GET_DOC <span class="token operator">=</span> new InjectionToken<span class="token punctuation">(</span>
    <span class="token string">'firestore-get-doc'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            const <span class="token number">db</span> <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_FIRESTORE<span class="token punctuation">)</span><span class="token punctuation">;</span>
            const platformID <span class="token operator">=</span> inject<span class="token punctuation">(</span>PLATFORM_ID<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> async <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>path: string<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

                try {

                    const snap <span class="token operator">=</span> isPlatformBrowser<span class="token punctuation">(</span>platformID<span class="token punctuation">)</span>
                        ? await getDoc<span class="token punctuation">(</span>doc<span class="token punctuation">(</span><span class="token number">db</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">)</span>
                        : await getDocLite<span class="token punctuation">(</span>docLite<span class="token punctuation">(</span><span class="token number">db</span><span class="token punctuation">,</span> path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>snap<span class="token punctuation">.</span><span class="token keyword">exists</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> {
                        throw new Error<span class="token punctuation">(</span><span class="token punctuation">`</span>Document at path <span class="token string">"${path}"</span> does <span class="token operator">not</span> exist<span class="token punctuation">.</span><span class="token punctuation">`</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    }
                    <span class="token keyword">return</span> {
                        <span class="token keyword">data</span>: snap<span class="token punctuation">.</span><span class="token keyword">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> T<span class="token punctuation">,</span>
                        error: <span class="token boolean">null</span>
                    }<span class="token punctuation">;</span>

                } catch <span class="token punctuation">(</span><span class="token number">e</span><span class="token punctuation">)</span> {
                    
                    <span class="token keyword">return</span> {
                        <span class="token keyword">data</span>: <span class="token boolean">null</span><span class="token punctuation">,</span>
                        error: <span class="token number">e</span>
                    }<span class="token punctuation">;</span>
                }
            }
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="breakdown">Breakdown</h3><ol><li>First, we import our firebase config and parse the JSON data so it can be read.</li><li><code>firebase-app</code> makes sure we initialize Firebase only once.</li><li><code>firebase-auth</code> will return null if on the server. We only need to use it on the browser.</li><li><code>firebase-firestore</code> has two versions. The <em>Firestore Lite</em> package at <code>firebase/firestore/lite</code> will be faster, does not require TCP and will run in any environment. This means if you deploy to Vercel Edge, Deno, Cloudflare or Bun, it will still work!</li><li><code>firestore-get-doc</code> is just a shortcut for us to get rid of the boilerplate of asynchronously fetching a document.</li></ol><h2 id="authentication">Authentication</h2><p>We need an authentication service to handle login actions. This is only used on the client.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> {
    DestroyRef<span class="token punctuation">,</span>
    InjectionToken<span class="token punctuation">,</span>
    inject<span class="token punctuation">,</span>
    isDevMode<span class="token punctuation">,</span>
    signal
} <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> {
    GoogleAuthProvider<span class="token punctuation">,</span>
    <span class="token keyword">User</span><span class="token punctuation">,</span>
    onIdTokenChanged<span class="token punctuation">,</span>
    signInWithPopup<span class="token punctuation">,</span>
    signOut
} <span class="token keyword">from</span> <span class="token string">'firebase/auth'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { FIREBASE_AUTH } <span class="token keyword">from</span> <span class="token string">'./firebase.service'</span><span class="token punctuation">;</span>

export interface userData {
    photoURL: string <span class="token operator">|</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
    uid: string<span class="token punctuation">;</span>
    displayName: string <span class="token operator">|</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
    email: string <span class="token operator">|</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
}<span class="token punctuation">;</span>

export const <span class="token keyword">USER</span> <span class="token operator">=</span> new InjectionToken<span class="token punctuation">(</span>
    <span class="token string">'user'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {

            const auth <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_AUTH<span class="token punctuation">)</span><span class="token punctuation">;</span>
            const destroy <span class="token operator">=</span> inject<span class="token punctuation">(</span>DestroyRef<span class="token punctuation">)</span><span class="token punctuation">;</span>

            const <span class="token keyword">user</span> <span class="token operator">=</span> signal<span class="token operator">&lt;</span>{
                loading: <span class="token keyword">boolean</span><span class="token punctuation">,</span>
                <span class="token keyword">data</span>: userData <span class="token operator">|</span> <span class="token boolean">null</span><span class="token punctuation">,</span>
                error: Error <span class="token operator">|</span> <span class="token boolean">null</span>
            }<span class="token operator">&gt;</span><span class="token punctuation">(</span>{
                loading: <span class="token boolean">true</span><span class="token punctuation">,</span>
                <span class="token keyword">data</span>: <span class="token boolean">null</span><span class="token punctuation">,</span>
                error: <span class="token boolean">null</span>
            }<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// server environment</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>auth<span class="token punctuation">)</span> {
                <span class="token keyword">user</span><span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>{
                    <span class="token keyword">data</span>: <span class="token boolean">null</span><span class="token punctuation">,</span>
                    loading: <span class="token boolean">false</span><span class="token punctuation">,</span>
                    error: <span class="token boolean">null</span>
                }<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token keyword">user</span><span class="token punctuation">;</span>
            }

            <span class="token comment">// toggle loading</span>
            <span class="token keyword">user</span><span class="token punctuation">.</span><span class="token keyword">update</span><span class="token punctuation">(</span>_user <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>{
                <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>_user<span class="token punctuation">,</span>
                loading: <span class="token boolean">true</span>
            }<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            const unsubscribe <span class="token operator">=</span> onIdTokenChanged<span class="token punctuation">(</span>auth<span class="token punctuation">,</span>
                <span class="token punctuation">(</span>_user: <span class="token keyword">User</span> <span class="token operator">|</span> <span class="token boolean">null</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_user<span class="token punctuation">)</span> {
                        <span class="token keyword">user</span><span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>{
                            <span class="token keyword">data</span>: <span class="token boolean">null</span><span class="token punctuation">,</span>
                            loading: <span class="token boolean">false</span><span class="token punctuation">,</span>
                            error: <span class="token boolean">null</span>
                        }<span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token keyword">return</span><span class="token punctuation">;</span>
                    }

                    <span class="token comment">// map data to user data type</span>
                    const {
                        photoURL<span class="token punctuation">,</span>
                        uid<span class="token punctuation">,</span>
                        displayName<span class="token punctuation">,</span>
                        email
                    } <span class="token operator">=</span> _user<span class="token punctuation">;</span>
                    const <span class="token keyword">data</span> <span class="token operator">=</span> {
                        photoURL<span class="token punctuation">,</span>
                        uid<span class="token punctuation">,</span>
                        displayName<span class="token punctuation">,</span>
                        email
                    }<span class="token punctuation">;</span>

                    <span class="token comment">// print data in dev mode</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>isDevMode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> {
                        console<span class="token punctuation">.</span>log<span class="token punctuation">(</span><span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    }

                    <span class="token comment">// set store</span>
                    <span class="token keyword">user</span><span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>{
                        <span class="token keyword">data</span><span class="token punctuation">,</span>
                        loading: <span class="token boolean">false</span><span class="token punctuation">,</span>
                        error: <span class="token boolean">null</span>
                    }<span class="token punctuation">)</span><span class="token punctuation">;</span>
                }<span class="token punctuation">,</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

                    <span class="token comment">// handle error</span>
                    <span class="token keyword">user</span><span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>{
                        <span class="token keyword">data</span>: <span class="token boolean">null</span><span class="token punctuation">,</span>
                        loading: <span class="token boolean">false</span><span class="token punctuation">,</span>
                        error
                    }<span class="token punctuation">)</span><span class="token punctuation">;</span>

                }<span class="token punctuation">)</span><span class="token punctuation">;</span>

            destroy<span class="token punctuation">.</span>onDestroy<span class="token punctuation">(</span>unsubscribe<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">return</span> <span class="token keyword">user</span><span class="token punctuation">;</span>
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>

export const LOGIN <span class="token operator">=</span> new InjectionToken<span class="token punctuation">(</span>
    <span class="token string">'LOGIN'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            const auth <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_AUTH<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {
                <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>auth<span class="token punctuation">)</span> {
                    <span class="token keyword">return</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
                }
                <span class="token keyword">return</span> signInWithPopup<span class="token punctuation">(</span>
                    auth<span class="token punctuation">,</span>
                    new GoogleAuthProvider<span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">)</span><span class="token punctuation">;</span>
            }<span class="token punctuation">;</span>
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>

export const LOGOUT <span class="token operator">=</span> new InjectionToken<span class="token punctuation">(</span>
    <span class="token string">'LOGOUT'</span><span class="token punctuation">,</span>
    {
        providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
        factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
            const auth <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIREBASE_AUTH<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {
                <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>auth<span class="token punctuation">)</span> {
                    <span class="token keyword">return</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
                }
                <span class="token keyword">return</span> signOut<span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">;</span>
            }<span class="token punctuation">;</span>
        }
    }
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="breakdown-1">Breakdown</h3><ol><li><code>USER</code> will use <code>onIdTokenChanged</code> to get the latest user state and set it to a signal that is updated in real time. You can check loading states or errors. It gets destroyed when the component is unmounted by using <code>onDestroy</code>.</li><li><code>LOGIN</code> is a callable function to login with the Google provider. It is meant to be called from a button on the client.</li><li><code>LOGOUT</code> is the logout method that destroys the session on the client. It is also meant to be called from the client only.</li></ol><h2 id="layout">Layout</h2><p>We can edit the <code>app.ts</code> file to get our layout.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { RouterLink<span class="token punctuation">,</span> RouterOutlet } <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
  selector: <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  imports: <span class="token punctuation">[</span>RouterOutlet<span class="token punctuation">,</span> RouterLink<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template: <span class="token punctuation">`</span>
  <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"pt-5"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>router<span class="token operator">-</span>outlet <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>  
  <span class="token operator">&lt;</span>nav class<span class="token operator">=</span><span class="token string">"flex gap-3 justify-center mt-5"</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token number">a</span> routerLink<span class="token operator">=</span><span class="token string">"/"</span><span class="token operator">&gt;</span>Home<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token number">a</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token number">a</span> routerLink<span class="token operator">=</span><span class="token string">"/about"</span><span class="token operator">&gt;</span>About<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token number">a</span><span class="token operator">&gt;</span>
      <span class="token operator">&lt;</span><span class="token number">a</span> routerLink<span class="token operator">=</span><span class="token string">"/wall"</span><span class="token operator">&gt;</span>Login Wall<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token number">a</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>nav<span class="token operator">&gt;</span>
  <span class="token punctuation">`</span><span class="token punctuation">,</span>
}<span class="token punctuation">)</span>
export class AppComponent { }
</code></pre><ol><li><code>Home</code> will display our login state and profile.</li><li><code>About</code> will display the About information from the server OR the client, whether or not we are logged in. It also populates the schema and meta tags so that it can be SEO friendly.</li><li><code>Login Wall</code> will ONLY work when a user is logged in. You do not need to load data directly from the server, as Firebase has Firebase Rules for that, and SEO is unnecessary behind a login wall.</li></ol><h2 id="home">Home</h2><p>For the home component, we only need to inject the <code>user</code> and <code>login</code> tokens from our auth service.</p><h3 id="home.component.ts">home.component.ts</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component<span class="token punctuation">,</span> inject } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ProfileComponent } <span class="token keyword">from</span> <span class="token string">'@components/profile/profile.component'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { LOGIN<span class="token punctuation">,</span> <span class="token keyword">USER</span> } <span class="token keyword">from</span> <span class="token string">'@lib/firebase/auth.service'</span><span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
  selector: <span class="token string">'app-home'</span><span class="token punctuation">,</span>
  standalone: <span class="token boolean">true</span><span class="token punctuation">,</span>
  imports: <span class="token punctuation">[</span>ProfileComponent<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl: <span class="token string">'./home.component.html'</span>
}<span class="token punctuation">)</span>
export class HomeComponent {
  <span class="token keyword">user</span> <span class="token operator">=</span> inject<span class="token punctuation">(</span><span class="token keyword">USER</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  login <span class="token operator">=</span> inject<span class="token punctuation">(</span>LOGIN<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
</code></pre><h3 id="home.component.html">home.component.html</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"text-center"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold my-3"</span><span class="token operator">&gt;</span>Analog Firebase App<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>

    <span class="token variable">@if</span> <span class="token punctuation">(</span><span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>loading<span class="token punctuation">)</span> {

    <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>Loading<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>

    } <span class="token variable">@else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">data</span><span class="token punctuation">)</span> {

    <span class="token operator">&lt;</span>app<span class="token operator">-</span>profile <span class="token operator">/</span><span class="token operator">&gt;</span>

    } <span class="token variable">@else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>error<span class="token punctuation">)</span> {

    <span class="token operator">&lt;</span>p class<span class="token operator">=</span><span class="token string">"text-red-500"</span><span class="token operator">&gt;</span>Error: {{ <span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>error?<span class="token punctuation">.</span>message }}<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>

    } <span class="token variable">@else</span> {

    <span class="token operator">&lt;</span>button <span class="token keyword">type</span><span class="token operator">=</span><span class="token string">"button"</span> class<span class="token operator">=</span><span class="token string">"border p-2 rounded-md text-white bg-red-600"</span> <span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">"login()"</span><span class="token operator">&gt;</span>
        Signin <span class="token keyword">with</span> Google
    <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>

    }
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
</code></pre><p>We display errors when necessary, and we show the <code>app-profile</code> component on success.</p><h3 id="profile">Profile</h3><p>Because we are logged in already, we only need to show logout and user info.</p><h3 id="profile.component.ts">profile.component.ts</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component<span class="token punctuation">,</span> inject } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { LOGOUT<span class="token punctuation">,</span> <span class="token keyword">USER</span> } <span class="token keyword">from</span> <span class="token string">'@lib/firebase/auth.service'</span><span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
  selector: <span class="token string">'app-profile'</span><span class="token punctuation">,</span>
  standalone: <span class="token boolean">true</span><span class="token punctuation">,</span>
  imports: <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl: <span class="token string">'./profile.component.html'</span>
}<span class="token punctuation">)</span>
export class ProfileComponent {
  <span class="token keyword">user</span> <span class="token operator">=</span> inject<span class="token punctuation">(</span><span class="token keyword">USER</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  logout <span class="token operator">=</span> inject<span class="token punctuation">(</span>LOGOUT<span class="token punctuation">)</span><span class="token punctuation">;</span>
}

</code></pre><h3 id="profile.component.html">profile.component.html</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex flex-col gap-3 items-center"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>h3 class<span class="token operator">=</span><span class="token string">"font-bold"</span><span class="token operator">&gt;</span>Hi {{ <span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">data</span>?<span class="token punctuation">.</span>displayName }}<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img <span class="token punctuation">[</span>src<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"user().data?.photoURL"</span> width<span class="token operator">=</span><span class="token string">"100"</span> height<span class="token operator">=</span><span class="token string">"100"</span> alt<span class="token operator">=</span><span class="token string">"user avatar"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>Your userID <span class="token operator">is</span> {{ <span class="token keyword">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">data</span>?<span class="token punctuation">.</span>uid }}<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>button <span class="token keyword">type</span><span class="token operator">=</span><span class="token string">"button"</span> class<span class="token operator">=</span><span class="token string">"border p-2 rounded-md text-white bg-lime-600"</span> <span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token operator">=</span><span class="token string">"logout()"</span><span class="token operator">&gt;</span>
        Logout
    <span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
</code></pre><p>Buttons can only be called on the server.</p><h2 id="about-data">About Data</h2><p>Our About data is the key to SEO.</p><h3 id="about-resolver">About Resolver</h3><p>We need to force our Angular component to wait for our About data to be fetched. The correct place to do this is in an Angular Resolver, although you can use <a target="_blank" href="https://angular.dev/api/core/PendingTasks">Pending Tasks</a> in more complex situations.</p><h3 id="about-data.resolver.ts">about-data.resolver.ts</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { inject<span class="token punctuation">,</span> isDevMode } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { Meta<span class="token punctuation">,</span> Title } <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ResolveFn } <span class="token keyword">from</span> <span class="token string">'@angular/router'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { FIRESTORE_GET_DOC } <span class="token keyword">from</span> <span class="token string">'@lib/firebase/firebase.service'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { useAsyncTransferState } <span class="token keyword">from</span> <span class="token string">'@lib/utils'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { <span class="token keyword">Schema</span> } <span class="token keyword">from</span> <span class="token string">'./schema.service'</span><span class="token punctuation">;</span>

export <span class="token keyword">type</span> AboutDoc <span class="token operator">=</span> {
    name: string<span class="token punctuation">;</span>
    description: string<span class="token punctuation">;</span>
}<span class="token punctuation">;</span>

export const aboutDataResolver: ResolveFn<span class="token operator">&lt;</span>AboutDoc<span class="token operator">&gt;</span> <span class="token operator">=</span> async <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

    <span class="token keyword">return</span> useAsyncTransferState<span class="token punctuation">(</span><span class="token string">'about'</span><span class="token punctuation">,</span> async <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

        const getDoc <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIRESTORE_GET_DOC<span class="token punctuation">)</span><span class="token punctuation">;</span>

        const meta <span class="token operator">=</span> inject<span class="token punctuation">(</span>Meta<span class="token punctuation">)</span><span class="token punctuation">;</span>
        const title <span class="token operator">=</span> inject<span class="token punctuation">(</span>Title<span class="token punctuation">)</span><span class="token punctuation">;</span>
        const <span class="token keyword">schema</span> <span class="token operator">=</span> inject<span class="token punctuation">(</span><span class="token keyword">Schema</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        const {
            <span class="token keyword">data</span><span class="token punctuation">,</span>
            error
        } <span class="token operator">=</span> await getDoc<span class="token operator">&lt;</span>AboutDoc<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token string">'/about/ZlNJrKd6LcATycPRmBPA'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> {
            throw error<span class="token punctuation">;</span>
        }

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">data</span><span class="token punctuation">)</span> {
            throw new Error<span class="token punctuation">(</span><span class="token string">'No data found'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        }

        title<span class="token punctuation">.</span>setTitle<span class="token punctuation">(</span><span class="token keyword">data</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
        meta<span class="token punctuation">.</span>updateTag<span class="token punctuation">(</span>{
            name: <span class="token string">'description'</span><span class="token punctuation">,</span>
            content: <span class="token keyword">data</span><span class="token punctuation">.</span>description
        }<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">schema</span><span class="token punctuation">.</span>setSchema<span class="token punctuation">(</span>{
            <span class="token string">'@context'</span>: <span class="token string">'https://schema.org'</span><span class="token punctuation">,</span>
            <span class="token string">'@type'</span>: <span class="token string">'WebPage'</span><span class="token punctuation">,</span>
            name: <span class="token keyword">data</span><span class="token punctuation">.</span>name<span class="token punctuation">,</span>
            description: <span class="token keyword">data</span><span class="token punctuation">.</span>description
        }<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>isDevMode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> {
            console<span class="token punctuation">.</span>log<span class="token punctuation">(</span><span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        }

        <span class="token keyword">return</span> <span class="token keyword">data</span><span class="token punctuation">;</span>
    }<span class="token punctuation">)</span><span class="token punctuation">;</span>

}<span class="token punctuation">;</span>
</code></pre><p>This resolver uses all our utility files in one go. We fetch our Firestore document by providing the path, set the title, meta tag and schema before returning the data. We do this in a transfer state so that we only have to fetch the data once on the server. Bing!</p><h3 id="about-data.component.ts">about-data.component.ts</h3><p>We inject our transfer data from the resolver and display it.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { AboutDoc } <span class="token keyword">from</span> <span class="token string">'./about-data.resolver'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { injectResolver } <span class="token keyword">from</span> <span class="token string">'@lib/utils'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { AsyncPipe } <span class="token keyword">from</span> <span class="token string">'@angular/common'</span><span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
    selector: <span class="token string">'app-about-data'</span><span class="token punctuation">,</span>
    standalone: <span class="token boolean">true</span><span class="token punctuation">,</span>
    imports: <span class="token punctuation">[</span>AsyncPipe<span class="token punctuation">]</span><span class="token punctuation">,</span>
    template: <span class="token punctuation">`</span>
    <span class="token variable">@if</span> <span class="token punctuation">(</span>about <span class="token operator">|</span> async<span class="token punctuation">;</span> <span class="token keyword">as</span> <span class="token keyword">data</span><span class="token punctuation">)</span> {
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex items-center justify-center my-5"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"border w-[400px] p-5 flex flex-col gap-3"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>{{ <span class="token keyword">data</span><span class="token punctuation">.</span>name }}<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>{{ <span class="token keyword">data</span><span class="token punctuation">.</span>description }}<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>p class<span class="token operator">=</span><span class="token string">"text-center"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token number">a</span> href<span class="token operator">=</span><span class="token string">"https://validator.schema.org/#url=https%3A%2F%2Fultimate-analog-firebase.vercel.app%2Fabout"</span> target<span class="token operator">=</span><span class="token string">"_blank"</span> class<span class="token operator">=</span><span class="token string">"text-blue-600 underline"</span><span class="token operator">&gt;</span>Validate <span class="token keyword">Schema</span><span class="token punctuation">.</span>org Metadata<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token number">a</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
    }
    <span class="token punctuation">`</span>
}<span class="token punctuation">)</span>
export <span class="token keyword">default</span> class AboutDataComponent {
    about <span class="token operator">=</span> injectResolver<span class="token operator">&lt;</span>AboutDoc<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token string">'data'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
</code></pre><p>We must import the <code>AsyncPipe</code> and add it to an <code>@if</code> statement. Then we can display our data. The server will wait.</p><p> Notice we use a standalone component here. Sometimes it is good to mix and match depending on readability or preference.</p><h2 id="login-wall">Login Wall</h2><p>We do not want to fetch on the server, but on the client only. The <code>resource</code> directive gives us the perfect tools to handle loading and error states.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> isDevMode<span class="token punctuation">,</span> resource } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { FIRESTORE_GET_DOC } <span class="token keyword">from</span> <span class="token string">'@lib/firebase/firebase.service'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { FirebaseError } <span class="token keyword">from</span> <span class="token string">'firebase/app'</span><span class="token punctuation">;</span>

export <span class="token keyword">type</span> WallDoc <span class="token operator">=</span> {
    name: string<span class="token punctuation">;</span>
    description: string<span class="token punctuation">;</span>
}<span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
    selector: <span class="token string">'app-wall-data'</span><span class="token punctuation">,</span>
    standalone: <span class="token boolean">true</span><span class="token punctuation">,</span>
    imports: <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    template: <span class="token punctuation">`</span>
    <span class="token variable">@if</span> <span class="token punctuation">(</span>wall<span class="token punctuation">.</span>isLoading<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> {
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex items-center justify-center my-5"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>Loading<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    } <span class="token variable">@else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>wall<span class="token punctuation">.</span><span class="token keyword">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">=</span><span class="token operator">=</span> <span class="token string">'resolved'</span><span class="token punctuation">)</span> {
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex items-center justify-center my-5"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"border w-[400px] p-5 flex flex-col gap-3"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>{{ wall<span class="token punctuation">.</span><span class="token keyword">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span>?<span class="token punctuation">.</span>name }}<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>{{ wall<span class="token punctuation">.</span><span class="token keyword">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span>?<span class="token punctuation">.</span>description }}<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    } <span class="token variable">@else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>wall<span class="token punctuation">.</span><span class="token keyword">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">=</span><span class="token operator">=</span> <span class="token string">'error'</span><span class="token punctuation">)</span> {
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex items-center justify-center my-5"</span><span class="token operator">&gt;</span>
        <span class="token variable">@if</span> <span class="token punctuation">(</span>wall<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token punctuation">)</span>?<span class="token punctuation">.</span>message <span class="token operator">=</span><span class="token operator">=</span><span class="token operator">=</span> <span class="token string">'permission-denied'</span><span class="token punctuation">)</span> {
            <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>You must <span class="token number">be</span> logged <span class="token operator">in</span> <span class="token keyword">to</span> <span class="token keyword">view</span> this<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
        } <span class="token variable">@else</span> {
            <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>An error occurred: {{ wall<span class="token punctuation">.</span>error<span class="token punctuation">(</span><span class="token punctuation">)</span>?<span class="token punctuation">.</span>message }}<span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
        }
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    } <span class="token variable">@else</span> {
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"flex items-center justify-center my-5"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>h1 class<span class="token operator">=</span><span class="token string">"text-3xl font-semibold"</span><span class="token operator">&gt;</span>You must <span class="token number">be</span> logged <span class="token operator">in</span> <span class="token keyword">to</span> <span class="token keyword">view</span> this<span class="token operator">!</span><span class="token operator">&lt;</span><span class="token operator">/</span>h1<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
    }
    <span class="token punctuation">`</span>
}<span class="token punctuation">)</span>
export <span class="token keyword">default</span> class WallDataComponent {

    getDoc <span class="token operator">=</span> inject<span class="token punctuation">(</span>FIRESTORE_GET_DOC<span class="token punctuation">)</span><span class="token punctuation">;</span>

    wall <span class="token operator">=</span> resource<span class="token punctuation">(</span>{

        loader: async <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {

            const {
                <span class="token keyword">data</span><span class="token punctuation">,</span>
                error
            } <span class="token operator">=</span> await this<span class="token punctuation">.</span>getDoc<span class="token operator">&lt;</span>WallDoc<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token string">'/secret/tJKWxu0ls6R0RyH1Atpb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> {

                <span class="token keyword">if</span> <span class="token punctuation">(</span>error instanceof FirebaseError<span class="token punctuation">)</span> {

                    <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">.</span>code <span class="token operator">=</span><span class="token operator">=</span><span class="token operator">=</span> <span class="token string">'permission-denied'</span><span class="token punctuation">)</span> {
                        throw new Error<span class="token punctuation">(</span>error<span class="token punctuation">.</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    }

                    console<span class="token punctuation">.</span>error<span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    throw error<span class="token punctuation">;</span>
                }
            }

            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">data</span><span class="token punctuation">)</span> {
                throw new Error<span class="token punctuation">(</span><span class="token string">'No data returned'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            }

            <span class="token keyword">if</span> <span class="token punctuation">(</span>isDevMode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> {
                console<span class="token punctuation">.</span>log<span class="token punctuation">(</span><span class="token keyword">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            }

            <span class="token keyword">return</span> <span class="token keyword">data</span><span class="token punctuation">;</span>
        }
    }<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
</code></pre><ul><li>We fetch our document in <code>resource({ loader: ... });</code>.</li><li>We throw and error to use it in our template.</li><li>Our signals are:
        <ul><li><code>wall.isLoading()</code></li><li><code>wall.status() === 'resolved'</code></li><li><code>wall.status() === 'error'</code></li></ul></li><li>We check for the specific <code>permission-denied</code> error to show our not logged-in message.</li></ul><h2 id="firebase-rules">Firebase Rules</h2><p>For our login wall, we can create a Firestore Rule to prevent a document from being read unless the user is logged in. We could equally add roles, etc.</p><pre class=" language-sql"><code class="prism  language-sql">service cloud<span class="token punctuation">.</span>firestore {

  <span class="token keyword">match</span> <span class="token operator">/</span><span class="token keyword">databases</span><span class="token operator">/</span>{<span class="token keyword">database</span>}<span class="token operator">/</span>documents {
    <span class="token keyword">match</span> <span class="token operator">/</span>{document<span class="token operator">=</span><span class="token operator">*</span><span class="token operator">*</span>} {
    
      <span class="token keyword">match</span> <span class="token operator">/</span>secret<span class="token operator">/</span>{document} {
      allow <span class="token keyword">read</span>: <span class="token keyword">if</span> request<span class="token punctuation">.</span>auth <span class="token operator">!=</span> <span class="token boolean">null</span><span class="token punctuation">;</span>
      }
      
      <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
</code></pre><h2 id="final-thoughts">Final Thoughts</h2><p>I firmly believe this is all you need for 99% of Firebase apps. I have written articles on <a target="_blank" href="https://code.build/p/sveltekit-todo-app-with-firebase-admin-tqdc5j">Firebase Admin Setup</a> and <a target="_blank" href="https://code.build/p/firebase-now-works-on-the-server-eFtYMt">Service Worker with Firebase Lite</a> if you want to go down that rabbit hole, but you really don&rsquo;t need them.</p><p> You also really don&rsquo;t need real-time data unless you&rsquo;re building a chat app or using notifications, but that can be easily added.</p><p>This basic setup, using Angular 20+, signals, pure Firebase, Firestore Lite and clean injection tokens, should cover all your needs.</p><p><strong>Repo:</strong> <a target="_blank" href="https://github.com/jdgamble555/ultimate-analog-firebase">GitHub</a><br /><strong>Demo:</strong> <a target="_blank" href="https://ultimate-analog-firebase.vercel.app/">Vercel Edge Functions</a>
</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">OG Image Generation in AnalogJS</h4></div><div class="col-8"><p class="u-fs16 u-mb0"><a target="_blank" href="https://www.telerik.com/blogs/og-image-generation-analogjs">AnalogJS can now generate custom OG Images</a> in Angular on the server for dynamic image sharing. Learn how!</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17277992.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:6efc6556-25b3-4e9f-a836-e533c76c4264</id>
    <title type="text">Image Optimization in Angular Applications</title>
    <summary type="text">In this guide, we will see how to use Angular’s NgOptimizedImage directive to address some common image optimization concerns effortlessly.</summary>
    <published>2026-02-10T18:11:37Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Christian Nwamba </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17273824/image-optimization-angular-applications"/>
    <content type="text"><![CDATA[<p><span class="featured">In this guide, we will see how to use Angular&rsquo;s NgOptimizedImage directive to address some common image optimization concerns effortlessly.</span></p><p>There is hardly a website you will come across that does not have images, and this shows how indispensable they are in driving sales, enhancing credibility and improving user engagement.</p><p>While this is good news, on the other hand, images contribute to 42% of why websites are slow, as they take up significant bandwidth and are a major contributor to why websites do not meet the standard requirements for performance on the internet, as defined by Google&rsquo;s Core Web Vitals and its LCP metric.</p><p>This raises the important question of how best to take advantage of images. The answer is image optimization&mdash;a set of techniques that enable web developers to effectively use images and deliver the best user experience.</p><p>Framework developers, having understood the difficulties developers face while using images, have created tools to do the heavy lifting. In this article, we will go through the use of Angular&rsquo;s <code>NgOptimizedImage</code> directive, which builds on top of the traditional <code>&lt;img/&gt;</code> element with some enhancements. We will see how it can be used to address some common image optimization concerns effortlessly.</p><h2 id="things-we-need-to-optimize-when-using-images">Things We Need to Optimize When Using Images</h2><p>This section will discuss a set of areas that require attention to get it right with images, irrespective of the platform on which images are used. The browser provides two main tags to work with images: <code>&lt;picture/&gt;</code> and <code>&lt;img/&gt;</code>, with the latter being the preferred option.</p><p>As we go over these areas and the techniques used, where necessary we will also specify attributes provided by the <code>img</code> element that can be used to solve these problems.</p><p>We will split our optimization concerns into three categories:</p><ul><li>Those that have to do with a single image</li><li>Working with multiple images</li><li>Meeting standards</li></ul><h2 id="single-image">Single Image</h2><p>Optimizing a single image involves the following:</p><h3 id="format">Format</h3><p>Different image formats provide different compression levels and are best suited for different purposes:</p><ul><li>Verify that the right image format is used for the right purpose. For example, PNGs are best suited for graphic content, and AVIF or WebP should be preferred over older formats like JPEG, since they yield smaller file sizes with greater quality and reduced bandwidth.</li><li>For local images, you may need to use tools like <a target="_blank" href="https://www.adobe.com/uk/products/photoshop.html">Photoshop</a>, <a target="_blank" href="https://www.ffmpeg.org/">FFmpeg</a>, <a target="_blank" href="https://squoosh.app/">Squoosh</a> or another media manipulation tool to convert between formats before using them on your website. However, if images are stored on a CDN provisioned by some provider (e.g., Cloudinary), tools are provided to convert between formats.</li></ul><h3 id="resolution-switching-and-viewport-based-sizing">Resolution Switching and Viewport-Based Sizing</h3><p>Devices have different resolutions and pixel densities/ratios. Developers need to serve the right image to the right device.</p><p>Device pixel ratio, in simple terms, refers to how many of the device&rsquo;s physical pixels can fit into the dimensions of a CSS pixel. So a device with a higher DPR should be served a high-resolution image and vice versa.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image-showing-viewport.png?sfvrsn=32c6da35_2" title="Image showing viewport based sizing" alt="Image showing viewport based sizing" /></p><p>The <code>img</code> element ships with two main attributes to solve this problem. The <code>srcset</code> attribute allows developers to configure the candidate images to enable browsers to select the right one.</p><h2 id="multiple-images">Multiple Images</h2><p>When working with multiple images, optimization concerns involve the following:</p><ul><li>Lazy loading images</li><li>Giving priority to more important images</li></ul><h3 id="lazy-loading-images">Lazy Loading Images</h3><p>Lazy loading means that only the required image(s) are presented to the user, which saves bandwidth and reduces the page&rsquo;s critical rendering path, which in turn lowers its load time. The <code>img</code> tag ships with the loading attribute, which can be set to &ldquo;lazy&rdquo; to achieve this behavior.</p><p>Low-quality image placeholders should be used in conjunction with lazy loading to minimize the perceived loading time while the browser downloads the actual image. For local images, developers may need to generate placeholders manually or use specialized tools. When using a remote provider, some JavaScript is still required to display the placeholder before the browser downloads the actual image.</p><h3 id="giving-priority-to-more-important-images">Giving Priority to More Important Image(s)</h3><p>Not all images on a page are of equal importance (e.g., LCP&mdash;Largest Contentful Paint&mdash;images). Developers should prioritize more important images over less important ones. The <code>img</code> tag provides the loading and <code>fetchPriority</code> attributes to solve these issues, together with preloading the image using the <code>link</code> element.</p><h2 id="optimizing-for-standard">Optimizing for Standard</h2><p>Optimizing a standard image involves the following:</p><ul><li>Optimize for LCP (Largest Contentful Paint)</li><li>Optimize for CLS (Cumulative Layout Shift)</li></ul><h3 id="optimize-for-lcp">Optimize for LCP</h3><p>The LCP of a webpage is a measure of how long it takes to display its main content&mdash;it could be an image, a section, a video, etc. A good LCP is within the range of 0-2.5s.</p><p>When the LCP element on a page is an image, developers should load that image to the webpage as soon as possible while also verifying that the image size is optimized. The <code>img</code> element provides us with loading and <code>fetchPriority</code> attributes. The <code>link</code> element can also be used to prioritize fetching important assets, such as images on the webpage.</p><h3 id="optimize-for-cls">Optimize for CLS</h3><p>Layout shifts occur when there is a sudden movement of one or more elements on the webpage because something changed or was introduced to the DOM while the webpage was still loading. With images, it occurs when the browser loads the image at a later time after loading some of the other content on the page, and when space was not reserved for the image. So after the image is added to the DOM, other elements are displaced.</p><p>When images are not used as background images, it is essential to define a width and height for the image so that the space is reserved for the image, even when the load time is delayed.</p><h2 id="the-ngoptimizedimage-directive">The NgOptimizedImage Directive</h2><p>We have discussed the different things we need to optimize when using images, and those that we can resolve using combinations of one or more attributes provided by the <code>img</code> element. One might wonder why we still need the <code>NgOptimizedImage</code> directive. Let&rsquo;s go over a few points.</p><p>The <code>NgOptimizedImage</code> directive builds on top of the <code>img</code> element and enhances it in the following ways:</p><ul><li>First, out of the box, it defines some important attributes when using the <code>img</code> element, so that developers do not have to remember to use them and can focus on building their applications.</li><li>It enables developers to use images optimized to meet standard requirements. By default, when using this directive, you are required to provide a <code>width</code> and <code>height</code> when images are not used as background images, so that layout shifts do not happen when loading images.</li><li>Out of the box, it integrates well with third-party media providers such as <a target="_blank" href="https://cloudinary.com/">Cloudinary</a>, <a target="_blank" href="https://imagekit.io/">ImageKit</a>, <a target="_blank" href="https://www.cloudflare.com/en-gb/">Cloudflare</a>, etc., so developers can easily use these services and get even better optimization.</li></ul><h2 id="ngoptimizedimage-in-action">NgOptimizedImage in Action</h2><p>Let&rsquo;s now see this directive in action. We will revisit the image optimization areas we listed earlier and see firsthand how to use the <code>NgOptimizedImage</code> directive in code. We will see how each step can be achieved with local and remote images.</p><h2 id="project-setup">Project Setup</h2><p>Run the command below to clone the starter project:</p><pre class=" language-shell"><code class="prism  language-shell">https://github.com/christiannwamba/ng-image-optimization
</code></pre><p>Our starter application has a few local images in its /public folder.</p><p>Apart from the root <code>app</code> component, the demo application defines three other components:</p><ul><li><code>local.component.ts</code>: The component in this file will show how to use local images.</li><li><code>remote-image.component.ts</code>: The component in this file will show how to use remote images.</li><li><code>local-and-remote-image.component.ts</code>: We will update this component later to see how to use local and remote images in one component using custom loaders.</li></ul><h2 id="basic-use">Basic Use</h2><p>Let&rsquo;s start by showing the basic use of this directive.</p><h3 id="local-image">Local Image</h3><p>Update your <code>local.component.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NgOptimizedImage <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"local-use"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    &lt;h3&gt;Local image&lt;/h3&gt;
    @for (img of localImages; track $index) {
    &lt;div style="padding-top: 700px"&gt;
      &lt;img width="800" height="600" [ngSrc]="img" /&gt;
    &lt;/div&gt;
    }
  `</span></span><span class="token punctuation">,</span>
  styles<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">``</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">LocalImageComponent</span> <span class="token punctuation">{</span>
  localImages <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token string">"2.webp"</span><span class="token punctuation">,</span>
    <span class="token string">"3.webp"</span><span class="token punctuation">,</span>
    <span class="token string">"4.jpg"</span><span class="token punctuation">,</span>
    <span class="token string">"5.jpg"</span><span class="token punctuation">,</span>
    <span class="token string">"6.jpg"</span><span class="token punctuation">,</span>
    <span class="token string">"7.jpg"</span><span class="token punctuation">,</span>
    <span class="token string">"8.jpg"</span><span class="token punctuation">,</span>
    <span class="token string">"9.jpg"</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="remote-image">Remote Image</h3><p>Update your <code>remote-image.component.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> NgOptimizedImage<span class="token punctuation">,</span> provideCloudinaryLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"remote-image-use"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token function">provideCloudinaryLoader</span><span class="token punctuation">(</span><span class="token string">"https://res.cloudinary.com/chrisnwamba1"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    &lt;h3&gt;Remote images&lt;/h3&gt;
    @for (img of remoteImages; track $index) {
    &lt;div class=""&gt;
      &lt;img width="800" height="600" [ngSrc]="img" /&gt;
    &lt;/div&gt;
    }
  `</span></span><span class="token punctuation">,</span>
  styles<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">``</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">RemoteImageComponent</span> <span class="token punctuation">{</span>
  remoteImages <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token string">"jcuh90sdncxwugdsqh40"</span><span class="token punctuation">,</span>
    <span class="token string">"qowugcszjxcdixvalvcp"</span><span class="token punctuation">,</span>
    <span class="token string">"err9wujrz1epkrhjbjtz"</span><span class="token punctuation">,</span>
    <span class="token string">"fypu0o7ea3ssvu4m97uh"</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>We start by importing the <code>NgOptimizedImage</code> directive and injecting it into the <code>imports</code> array.<br />In each component, we defined an array of local and remote images in the <code>localImages</code> and <code>remoteImages</code> variables, respectively.</p><p>Since we want our remote images to be managed for us by a third-party provider, <a target="_blank" href="https://cloudinary.com/">Cloudinary</a>, in our case, we created a <a target="_blank" href="https://cloudinary.com/users/register_free">Cloudinary account</a> and uploaded a few images there.</p><blockquote><p>Feel free to use your preferred media provider solution; we just chose to go with Cloudinary in this article.</p></blockquote><p>To work with remote images, we make use of loaders, which are just functions that resolve to URLs. We can create custom loaders or use those that are supported by default. We used the Cloudinary loader by injecting <code>provideCloudinaryLoader</code>, which we fed the base URL pointing to our cloud name.</p><p>We used the <code>ngSrc</code> property to set the image source. It is mandatory to define a <code>width</code> and <code>height</code> for images; this helps prevent layout shifts if the image is delayed during loading. Failure to do so will likely result in errors.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/width-and-height-properties.png?sfvrsn=69237b92_2" title="The width and height properties are compulsory for images that are not used as background images" alt="The width and height properties are compulsory for images that are not used as background images" /></p><p>You can start your application server by running <code>npm run start</code>. If you go ahead and inspect the <code>img</code> elements, you will notice that both local and remote images are lazy-loaded by default, as indicated by the <code>loading="lazy"</code> attribute, and there is no priority assigned to any image as specified by <code>fetchPriority="auto"</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/images-are-lazy-loaded.png?sfvrsn=cb8a14d3_2" title="Images are lazy loaded by default" alt="Images are lazy loaded by default" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/lazy-loading-in-action.gif?sfvrsn=d27b104d_2" title="Lazy loading in action" alt="Lazy loading in action" /></p><p>By default, the <code>srcset</code> attribute is added for remote images, and it defines candidate images for different DPRs.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/scrset-attribute-added-by-default.png?sfvrsn=48f09976_2" title="The scrset attribute is added by default for remote images with candidate images for different device densities" alt="The scrset attribute is added by default for remote images with candidate images for different device densities" /></p><p>Just by using the <code>ngSrc</code> attribute, the benefits of the <code>NgOptimizedImage</code> directive are immediately obvious. Let&rsquo;s now proceed to make some tweaks in our app to address the following areas:</p><ul><li>Using images as backgrounds</li><li>Lazy loading with placeholders</li><li>Loading high-priority images (improving LCP)</li><li>Resolution switching and viewport-based sizing</li></ul><h2 id="using-images-as-backgrounds">Using Images as Backgrounds</h2><p>Update the <code>local.component.ts</code> file with the following:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'local-use'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> `
  <span class="token operator">&lt;</span>div
  style<span class="token operator">=</span>"
    width<span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>
    height<span class="token punctuation">:</span> 700px<span class="token punctuation">;</span>
    overflow<span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
    position<span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
    margin<span class="token operator">-</span>inline<span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
    margin<span class="token operator">-</span>top<span class="token punctuation">:</span>700px<span class="token punctuation">;</span>
    padding<span class="token punctuation">:</span>30px<span class="token punctuation">;</span>
  "
<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>img
    fill
    <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"localImages[3]"</span>
    style<span class="token operator">=</span><span class="token string">"object-fit: cover; z-index: -1"</span>
  <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>H1<span class="token operator">&gt;</span>Hello<span class="token operator">&lt;</span><span class="token operator">/</span>H1<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>p<span class="token operator">&gt;</span>testing Backgrounds<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
</code></pre><p>By using the <code>fill</code> attribute, we can use images as backgrounds. This property overlays the image in its parent container using CSS. The <code>fill</code> attribute does not require us to specify a <code>width</code> or <code>height</code> property.</p><p>Here is a sample output:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image-as-background.png?sfvrsn=e0ba928_2" title="Image as background" alt="Image as background" /></p><h2 id="lazy-loading-with-placeholders">Lazy Loading with Placeholders</h2><h3 id="local-image-1">Local Image</h3><pre class=" language-ts"><code class="prism  language-ts"><span class="token operator">&lt;</span>h3<span class="token operator">&gt;</span>Local image<span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
    width<span class="token operator">=</span><span class="token string">"800"</span>
    height<span class="token operator">=</span><span class="token string">"600"</span>
    <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"localImages[3]"</span>
    placeholder<span class="token operator">=</span><span class="token string">"data:image/webp;base64,UklGRtAAAABXRUJQVlA4IMQAAABwBQCdASoeABYAPn04lEeko6IhN/qoAJAPiWUAtOmMvNuEG3k3qonsrAxlVBwKRSuctL6AAP5RW9WtEC0SDum4fF68ZQfeqBp3ieyso2Hc2ynsYXNcHAVa/DMTVvEUDdP0bRJtvmL3wvsyJ806MJRwREZAAVSaRrRK08CE6p8y76jW+EO/e7rKmFK5yUhVi3z7XYbOSbwkJ+X7ferG15xGCnyYvNIHoozVzX9IOCk0RxXcw5ZqEee3QgU+m05NtntkAAAA"</span>
  <span class="token operator">/</span><span class="token operator">&gt;</span>
</code></pre><p>For local images, the image <code>placeholder</code> property must be manually set to a data URL as shown above. It is recommended that data URLs should be kept within 4KB in size. You can use tools like <a target="_blank" href="https://www.ffmpeg.org/">FFmpeg</a> or visit websites like <a target="_blank" href="https://blurred.dev/">blurred.dev</a> to generate placeholders. Failure to use a data URL will generate an error.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/lazy-loading-local-images-with-placeholders.gif?sfvrsn=f251fb86_2" title="Lazy loading local images with placeholders" alt="Lazy loading local images with placeholders" /></p><h3 id="remote-image-1">Remote Image</h3><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">for</span> <span class="token punctuation">(</span>img <span class="token keyword">of</span> remoteImages<span class="token punctuation">;</span> track $index<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">""</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
      width<span class="token operator">=</span><span class="token string">"800"</span>
      height<span class="token operator">=</span><span class="token string">"590"</span>
      <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img"</span>
      placeholder
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><p>For remote images, just by setting the <code>placeholder</code> property, the loader generates a placeholder URL for all our images.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/placeholder-for-remote-images.gif?sfvrsn=67e887a8_2" title="Using placeholder for remote images" alt="Using placeholder for remote images" /></p><p>By default, placeholders have a width of 30 px in the generated URL as shown in the image below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/width-set-by-default.png?sfvrsn=b01118a0_2" title="Placeholder image has width set by default" alt="Placeholder image has width set by default" /></p><h2 id="customizing-placeholders">Customizing Placeholders</h2><h3 id="width">Width</h3><p>We can customize the width of placeholders by using the <code>IMAGE_CONFIG</code> injection token. This is only applicable when using remote images.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> IMAGE_CONFIG<span class="token punctuation">,</span> NgOptimizedImage<span class="token punctuation">,</span> provideCloudinaryLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'remote-image-use'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">provideCloudinaryLoader</span><span class="token punctuation">(</span><span class="token string">'https://res.cloudinary.com/dqydioa17'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      provide<span class="token punctuation">:</span> IMAGE_CONFIG<span class="token punctuation">,</span>
      useValue<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        placeholderResolution<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
</code></pre><p>If you set the <code>placeholderResolution</code> to <code>40</code>, you&rsquo;ll notice that the request URL is updated as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/customizing-the-width-of-placeholders.png?sfvrsn=39a22001_2" title="Customizing the width of placeholders" alt="Customizing the width of placeholders" /></p><h3 id="appearance">Appearance</h3><p>By default, placeholder images are blurred out. As we saw earlier, the <code>placeholderConfig</code> property is an object that allows us to enable or disable the blur effect. It accepts an object with only one property called <code>blur</code> and can be used for both remote and local images.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">for</span> <span class="token punctuation">(</span>img <span class="token keyword">of</span> remoteImages<span class="token punctuation">;</span> track $index<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token string">"padding-bottom: 900px"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
      width<span class="token operator">=</span><span class="token string">"800"</span>
      height<span class="token operator">=</span><span class="token string">"590"</span>
      <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img"</span>
      placeholder
      <span class="token punctuation">[</span>placeholderConfig<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"{blur:false}"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="loading-high-priority-images-improving-lcp">Loading High-Priority Images (Improving LCP)</h2><p>Websites may use one or more images, depending on the use case. Some images may need to be loaded earlier than others because an image could be the LCP element on the page. Hence, the need to give certain images a higher loading priority over others.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">for</span> <span class="token punctuation">(</span>img <span class="token keyword">of</span> remoteImages<span class="token punctuation">;</span> track $index<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token string">"padding-bottom: 900px"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
      width<span class="token operator">=</span><span class="token string">"800"</span>
      height<span class="token operator">=</span><span class="token string">"590"</span>
      <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img"</span>
      placeholder
      <span class="token punctuation">[</span>placeholderConfig<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"{blur:false}"</span>
      <span class="token punctuation">[</span>priority<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"$index ===2"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><p>For demonstration purposes, we set the <code>priority</code> property for the third image to <code>true</code>, simply assuming it is our LCP image.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/set-priority-property.png?sfvrsn=f6f31a05_2" title="Set priority property" alt="Set priority property" /></p><p>As seen above, this sets the <code>loading</code> and <code>fetchPriority</code> to <code>eager</code> and <code>high</code> respectively.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image-with-higher-priority.png?sfvrsn=d4fba38a_2" title="Image with higher priority is loaded before other resources" alt="Image with higher priority is loaded before other resources" /></p><p>As seen above, the image with higher priority is loaded before other resources. For the <code>img</code> element, it sets the <code>loading</code> and <code>fetchPriority</code> attributes on the image to <code>eager</code> and <code>high</code> respectively, so that the browser downloads the image as soon as possible and prioritizes it over any other resources being loaded.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/link-tag-is-added.png?sfvrsn=ad11415b_2" title="Link tag is added in the head section informing the browser to load the LCP image as soon as possible" alt="Link tag is added in the head section informing the browser to load the LCP image as soon as possible" /></p><p>Since we also enabled server-side rendering in our project, a <code>link</code> element is injected in the <code>head</code> section of the page. The <code>rel="preload"</code> instructs the browser to load the given asset (the image) as soon as possible.</p><h2 id="optimizing-quality-and-resolution">Optimizing Quality and Resolution</h2><h3 id="remote-images">Remote Images</h3><p>As stated earlier, optimizing images for quality and resolution involves two steps:</p><ul><li>Define one or more candidate images based on some criteria (e.g., width descriptors or DPR) using the <code>srcset</code> attribute</li><li>If our candidate images are width descriptors, we may optionally specify the criteria to help the browser select an image using the <code>sizes</code> prop</li></ul><p>We already established earlier that simply setting the <code>ngSrc</code> prop, the <code>srcset</code> attribute is populated. Different candidates are generated for device pixel ratios/densities in the <code>srcset</code> field, as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/density-descriptors-for-remote-images.png?sfvrsn=462229a3_2" title="Density descriptors for remote images" alt="Density descriptors for remote images" /></p><p>Another way to look at it is that by default, <code>ngSrcset="1x, 2x"</code>. The <code>ngSrcset</code> attribute allows us to define candidate images for the browser to choose from. It takes a comma-separated list of DPRs or width descriptors.</p><blockquote><p>Density descriptors or DPR can only be one of 1x, 2x, or 3x; anything outside these will result in an error. Width descriptors are a comma-separated list of numbers with a w suffix (e.g., 200w, 700w, 900w), which can be thought of as 200 px, 700 px and 900 px. However, px is not used.</p></blockquote><h2 id="define-different-resolutions-of-the-image-based-on-screen-widths">Define Different Resolutions of the Image Based on Screen Widths</h2><p>The <code>ngSrcset</code> attribute allows us to customize the candidate image URLs to be populated in the <code>img</code> element&rsquo;s <code>srcset</code> attribute using a shorter syntax. Let&rsquo;s update the <code>local.component.ts</code> file to see it in action:</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">for</span> <span class="token punctuation">(</span>img <span class="token keyword">of</span> remoteImages<span class="token punctuation">;</span> track $index<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token string">"padding-bottom: 900px"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
      width<span class="token operator">=</span><span class="token string">"800"</span>
      height<span class="token operator">=</span><span class="token string">"590"</span>
      <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img"</span>
      placeholder
      <span class="token punctuation">[</span>placeholderConfig<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"{blur:false}"</span>
      <span class="token punctuation">[</span>priority<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"$index ===0"</span>
      ngSrcset<span class="token operator">=</span><span class="token string">"200w, 700w, 900w"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><p>This tells the browser to generate three URLs at 200 px, 700 px and 900 px. When we look at the DOM, we see that the <code>srcset</code> attribute now defines three images based on the specified sizes, as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/the-srcset-attribute-populated.jpeg?sfvrsn=7f30d1aa_2" title="The srcset attribute is populated to include URLs pointing to images of different width" alt="The srcset attribute is populated to include URLs pointing to images of different width" /></p><p>When we define selection rules using the <code>sizes</code> prop, we instruct the browser how to select the candidate image in the <code>srcset</code> attribute based on available space.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token keyword">for</span> <span class="token punctuation">(</span>img <span class="token keyword">of</span> remoteImages<span class="token punctuation">;</span> track $index<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>div style<span class="token operator">=</span><span class="token string">"padding-bottom: 900px"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>img
      width<span class="token operator">=</span><span class="token string">"800"</span>
      height<span class="token operator">=</span><span class="token string">"590"</span>
      <span class="token punctuation">[</span>ngSrc<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img"</span>
      placeholder
      <span class="token punctuation">[</span>placeholderConfig<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"{blur:false}"</span>
      <span class="token punctuation">[</span>priority<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"$index ===0"</span>
      sizes<span class="token operator">=</span><span class="token string">"(max-width: 30em) 100vw"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><p>In the code above, we stated that if the viewport size is less than <code>30em</code>, the browser should display the image that is 100vw.</p><p>To put it into context, assuming 30em maps to 480 px, if the width of the device is less than or equal to 480 px, then the image to be displayed is the one at 100vw.</p><p>If 100vw for the target device maps to, say, 300 px, the browser looks at the list of images specified in the <code>srcset</code> and renders the one equal to or greater than, but closest to, 300 px. So if there were images of 900w, 650w and 1200w, the one at 650w is selected.</p><p>Specifying sizes informs the <code>NgOptimizedImage</code> directive that we want <code>width</code> descriptors. Since we didn&rsquo;t specify any above, like we did with <code>ngSrcset</code> previously, it automatically populates the <code>srcset</code> attribute with the default set of width descriptors it maintains, as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/default-width-descriptors.jpeg?sfvrsn=6d3c106e_2" title="Default width descriptors" alt="Default width descriptors" /></p><p>To customize the generated widths, we can either define an <code>ngSrcset</code> per image, as we did, or define them globally using the <code>IMAGE_CONFIG</code> injection token.</p><pre class=" language-ts"><code class="prism  language-ts">providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      provide<span class="token punctuation">:</span> IMAGE_CONFIG<span class="token punctuation">,</span>
      useValue<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      placeholderResolution<span class="token punctuation">:</span> <span class="token number">30</span><span class="token punctuation">,</span>
      breakpoints<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token number">500</span><span class="token punctuation">,</span> <span class="token number">600</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
</code></pre><p>When we refresh the application and inspect the DOM now, we notice that the <code>srcset</code> fields have been updated.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/custom-width-descriptors.jpeg?sfvrsn=e3734f1c_2" title="Defining custom width descriptors" alt="Defining custom width descriptors" /></p><h2 id="introducing-custom-loaders">Introducing Custom Loaders</h2><p>We already established that loaders are functions that receive some parameters and resolve a URL based on some predefined rules. So far, we have been using one of the default loaders (<code>provideCloudinaryLoader</code>), and this works well. However, there are situations when we have more complex requirements in our app that would require us to create a custom loader to achieve our goals.</p><p>Here is a list of things we want to support in our app and why we will be needing one:</p><ul><li>We want to use both local and remote images together in a single component</li><li>For our remote images, on our Cloudinary account, we want to be able to apply cool effects to image assets</li><li>We also want to be able to fetch a random image on the internet, store it in our Cloudinary account and apply effects to the image before rendering it in the browser</li></ul><p>Some other reasons why you might need to define an image loader include:</p><ul><li>Using multiple remote media provider solutions at once (e.g., <a target="_blank" href="https://cloudinary.com/">Cloudinary</a>, <a target="_blank" href="https://aws.amazon.com/s3/">S3</a> and <a target="_blank" href="https://www.imgix.com/">Imgix</a>)</li></ul><p>All the code we will write here will be in the <code>local-and-remote-image.component.ts</code> file. Update the file to look like so:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span>
  IMAGE_LOADER<span class="token punctuation">,</span>
  ImageLoaderConfig<span class="token punctuation">,</span>
  NgOptimizedImage<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"local-and-remote-image"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>NgOptimizedImage<span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      provide<span class="token punctuation">:</span> IMAGE_LOADER<span class="token punctuation">,</span>
      useValue<span class="token punctuation">:</span> <span class="token punctuation">(</span>config<span class="token punctuation">:</span> ImageLoaderConfig<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>config <span class="token operator">&amp;&amp;</span> config<span class="token punctuation">.</span>loaderParams <span class="token operator">&amp;&amp;</span> config<span class="token punctuation">.</span>loaderParams<span class="token punctuation">[</span><span class="token string">"local"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">return</span> <span class="token string">"/"</span> <span class="token operator">+</span> config<span class="token punctuation">.</span>src<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">const</span> deliveryType <span class="token operator">=</span>
          <span class="token punctuation">(</span>config<span class="token punctuation">.</span>loaderParams <span class="token operator">&amp;&amp;</span> config<span class="token punctuation">.</span>loaderParams<span class="token punctuation">[</span><span class="token string">"delivery_type"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">||</span>
          <span class="token string">"upload"</span><span class="token punctuation">;</span>
        <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token string">`https://res.cloudinary.com/dqydioa17/image/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>deliveryType<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>loaderParams <span class="token operator">&amp;&amp;</span> config<span class="token punctuation">.</span>loaderParams<span class="token punctuation">[</span><span class="token string">"tf"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          url <span class="token operator">+=</span> config<span class="token punctuation">.</span>loaderParams<span class="token punctuation">[</span><span class="token string">"tf"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>width<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          url <span class="token operator">+=</span> <span class="token template-string"><span class="token string">`/w_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>width<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        url <span class="token operator">+=</span> <span class="token template-string"><span class="token string">`/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>src<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> url<span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  template<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`
    &lt;div style="padding-top: 50px"&gt;
      &lt;h2&gt;local image&lt;/h2&gt;
      &lt;img
        width="800"
        height="600"
        [ngSrc]="'8.jpg'"
        [loaderParams]="{ local: true }"
      /&gt;
    &lt;/div&gt;
    &lt;div style="padding-top: 50px"&gt;
      &lt;h2&gt;remote image with effects&lt;/h2&gt;
      &lt;img
        width="800"
        height="600"
        [ngSrc]="'jcuh90sdncxwugdsqh40'"
        placeholder
        [loaderParams]="{ tf: '/e_enhance' }"
      /&gt;
    &lt;/div&gt;
    &lt;div style="padding-top: 50px"&gt;
      &lt;h2&gt;remote image with effects&lt;/h2&gt;
      &lt;img
        width="600"
        height="700"
        [ngSrc]="
          'https://upload.wikimedia.org/wikipedia/commons/1/13/Benedict_Cumberbatch_2011.png'
        "
        [loaderParams]="{ delivery_type: 'fetch', tf: '/e_vignette' }"
      /&gt;
    &lt;/div&gt;
  `</span></span><span class="token punctuation">,</span>
  styles<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">``</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">LocalAndRemoteImageComponent</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/working-with-local-and-remote-images.jpeg?sfvrsn=c7ec094a_2" title="Working with local and remote images" alt="Working with local and remote images" /></p><p>Our new component shows how we can use a custom loader to do amazing things. This component displays three images: a local one and two remote images with some effects applied. It starts by defining a custom loader, which is just a function bound to the <code>IMAGE_LOADER</code> injection token, which accepts an object that looks like so:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">interface</span> <span class="token class-name">ImageLoaderConfig</span> <span class="token punctuation">{</span>
  src<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
  width<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  isPlaceholder<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">boolean</span><span class="token punctuation">;</span>
  loaderParams<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
    <span class="token punctuation">[</span>key<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">]</span><span class="token punctuation">:</span> <span class="token keyword">any</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Of all these properties, the one we tinkered with most is the one called <code>loaderParams</code>, which allows us to define arbitrary key-value pairs to enable our loader to effectively decide how to resolve the URL. For the local image, we defined a local property.</p><p>For the remote images, we defined two:</p><ul><li><code>tf</code>: This holds image effects as defined in the Cloudinary docs</li><li><code>delivery_type</code>: Setting this to fetch means that the image is first fetched remotely, then added to our remote assets</li></ul><h2 id="conclusion">Conclusion</h2><p>Images are an integral part of the web. This guide shows how to use images effectively. Even though our focus was on the Angular framework, there are still a lot of takeaways to apply when using images in future projects.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Build Agentic Apps with Angular, Genkit and Kendo UI</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Get started on an <a target="_blank" href="https://www.telerik.com/blogs/build-agentic-apps-angular-genkit-kendo-ui-part-1">agentic Angular app with Genkit and Gemini</a>. We&rsquo;ll build out the ability for users to ask about the status of their order.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17273824.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:4a7d76df-c64c-47bf-b4d2-c54dce25cd20</id>
    <title type="text">OG Image Generation in AnalogJS</title>
    <summary type="text">AnalogJS can now generate custom OG Images in Angular on the server for dynamic image sharing.</summary>
    <published>2026-01-26T17:02:46Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Jonathan Gamble </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17263760/og-image-generation-analogjs"/>
    <content type="text"><![CDATA[<p><span class="featured">AnalogJS can now generate custom OG Images in Angular on the server for dynamic image sharing.</span></p><p>You may not know it, but Vercel released a package for Next.js called <a target="_blank" href="https://vercel.com/blog/introducing-vercel-og-image-generation-fast-dynamic-social-card-images">@vercel/og</a>. It is unfortunately not open-source, but almost every framework has implemented their own version using <a target="_blank" href="https://github.com/vercel/satori">Satori</a> under the hood.</p><h2 id="tldr">TL;DR</h2><p>Analog now has the ability to generate OG Images in Angular on the server for SEO purposes. You can customize them and generate them on the spot. While they only work in Node environments and have limited CSS capabilities, they are extremely useful and great for dynamic image sharing.</p><h2 id="what-is-an-og-image">What Is an OG Image?</h2><p>The <a target="_blank" href="https://ogp.me/">Open Graph Protocol</a> is an HTML pattern that allows you to describe your webpage in the meta tags for better search engine optimization.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:image"</span> content<span class="token operator">=</span><span class="token string">"https://ia.media-imdb.com/images/rock.jpg"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
</code></pre><p>When you create an image for each webpage, you allow preview images to be displayed. You can test a website with tools like <a target="_blank" href="https://www.opengraph.xyz/">Open Graph Preview</a>.</p><p> You can also add data with <a target="_blank" href="https://developer.x.com/en/docs/x-for-websites/cards/guides/getting-started">Twitter Cards</a> and <a target="_blank" href="http://Schema.org">Schema.org</a> images.</p><h3 id="twitter-card">Twitter Card</h3><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:card"</span> content<span class="token operator">=</span><span class="token string">"summary_large_image"</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:title"</span> content<span class="token operator">=</span><span class="token string">"Learn Latin with Interactive Flashcards"</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:description"</span> content<span class="token operator">=</span><span class="token string">"Build your Latin vocabulary through smart, progressive flashcards."</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:image"</span> content<span class="token operator">=</span><span class="token string">"https://example.com/images/latin-flashcards.jpg"</span><span class="token operator">&gt;</span>
<span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:image:alt"</span> content<span class="token operator">=</span><span class="token string">"Latin flashcards with English translations"</span><span class="token operator">&gt;</span>
</code></pre><h3 id="schema.org"><a target="_blank" href="http://Schema.org">Schema.org</a></h3><p>Or JSON-LD for schemas:</p><pre class=" language-sql"><code class="prism  language-sql">{
  <span class="token string">"@context"</span>: <span class="token string">"https://schema.org"</span><span class="token punctuation">,</span>
  <span class="token string">"@type"</span>: <span class="token string">"WebPage"</span><span class="token punctuation">,</span>
  <span class="token string">"name"</span>: <span class="token string">"How to Make French Toast"</span><span class="token punctuation">,</span>
  <span class="token string">"url"</span>: <span class="token string">"https://example.com/french-toast"</span><span class="token punctuation">,</span>
  <span class="token string">"image"</span>: <span class="token string">"https://example.com/images/french-toast.jpg"</span><span class="token punctuation">,</span>
  <span class="token string">"description"</span>: <span class="token string">"A simple guide to making delicious French toast."</span><span class="token punctuation">,</span>
  <span class="token string">"author"</span>: {
    <span class="token string">"@type"</span>: <span class="token string">"Person"</span><span class="token punctuation">,</span>
    <span class="token string">"name"</span>: <span class="token string">"Jane Doe"</span>
  }
}
</code></pre><h3 id="angular-image-directive">Angular Image Directive</h3><p>If you have an image on the site that can be created with CSS or Tailwind, you may also want to use it to generate dynamic images using the <a target="_blank" href="https://www.telerik.com/blogs/why-angulars-new-image-directive-worth-knowing">Angular Image Directive</a>.</p><h2 id="satori">Satori</h2><p>Vercel created a library called <a target="_blank" href="https://github.com/vercel/satori">Satori</a>, which converts HTML, CSS and Tailwind to an SVG image. It is a beautiful module, and it can run anywhere. However, it does not do every CSS function, nor does it convert the SVG to a PNG file, which requires rasterization. You must build a mini-canvas to convert the raw pixel data to PNG or JPG buffer. OG image parsers prefer PNG or SVG images.</p><h2 id="vercel-og">Vercel OG</h2><p>Vercel created a wrapper for this project. Unfortunately, it is not open-source and it only works on Next.js. It also uses JSX instead of pure HTML. However, there have been several implementations for it, including this one for AnalogJS.</p><h2 id="installation">Installation</h2><p>First, install AnalogJS. Then install the packages.</p><pre class=" language-sql"><code class="prism  language-sql">npm install satori satori<span class="token operator">-</span>html sharp <span class="token comment">--save</span>
</code></pre><h2 id="og-image-route">Og Image Route</h2><p>Create the file <code>og-image.ts</code> in <code>/server/routes/api</code>.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { defineEventHandler<span class="token punctuation">,</span> getQuery } <span class="token keyword">from</span> <span class="token string">'h3'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ImageResponse } <span class="token keyword">from</span> <span class="token string">'@analogjs/content/og'</span><span class="token punctuation">;</span>

export <span class="token keyword">default</span> defineEventHandler<span class="token punctuation">(</span>async <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> {
    const fontFile <span class="token operator">=</span> await <span class="token keyword">fetch</span><span class="token punctuation">(</span>
        <span class="token string">'https://cdn.jsdelivr.net/npm/@fontsource/geist-sans/files/geist-sans-latin-700-normal.woff'</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    const fontData: ArrayBuffer <span class="token operator">=</span> await fontFile<span class="token punctuation">.</span>arrayBuffer<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    const query <span class="token operator">=</span> getQuery<span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>

const template <span class="token operator">=</span> <span class="token punctuation">`</span>
    <span class="token operator">&lt;</span><span class="token operator">div</span> tw<span class="token operator">=</span>"flex flex<span class="token operator">-</span>col w<span class="token operator">-</span><span class="token keyword">full</span> h<span class="token operator">-</span><span class="token keyword">full</span> p<span class="token number">-12</span> items<span class="token operator">-</span>center <span class="token keyword">text</span><span class="token operator">-</span>center justify<span class="token operator">-</span>center <span class="token keyword">text</span><span class="token operator">-</span>white bg<span class="token operator">-</span><span class="token punctuation">[</span>${query<span class="token punctuation">[</span><span class="token string">'bgColor'</span><span class="token punctuation">]</span> ?? <span class="token string">'#5ce500'</span>}<span class="token punctuation">]</span><span class="token string">"&gt;
      &lt;h1 tw="</span>flex font<span class="token operator">-</span>bold <span class="token keyword">text</span><span class="token operator">-</span>8xl mb<span class="token number">-4</span> <span class="token keyword">text</span><span class="token operator">-</span>black<span class="token string">"&gt;${query['title'] ?? 'Progress &lt;span class="</span><span class="token keyword">text</span><span class="token operator">-</span>gray<span class="token number">-400</span><span class="token string">"&gt;Telerik&lt;/span&gt;'}&lt;/h1&gt;
      &lt;p tw="</span>flex <span class="token keyword">text</span><span class="token operator">-</span>5xl mb<span class="token number">-12</span> <span class="token keyword">text</span><span class="token operator">-</span>white"<span class="token operator">&gt;</span>${query<span class="token punctuation">[</span><span class="token string">'description'</span><span class="token punctuation">]</span> ?? <span class="token string">'Kendo UI'</span>}<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>
<span class="token punctuation">`</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> new ImageResponse<span class="token punctuation">(</span>template<span class="token punctuation">,</span> {
        debug: <span class="token boolean">true</span><span class="token punctuation">,</span>
        fonts: <span class="token punctuation">[</span>
            {
                name: <span class="token string">'Geist Sans'</span><span class="token punctuation">,</span>
                <span class="token keyword">data</span>: fontData<span class="token punctuation">,</span>
                weight: <span class="token number">700</span><span class="token punctuation">,</span>
                style: <span class="token string">'normal'</span><span class="token punctuation">,</span>
            }<span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
    }<span class="token punctuation">)</span><span class="token punctuation">;</span>
}<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We can pass data from the URL parameters through <code>getQuery</code>. Her we are using three variables:</p><ul><li>title</li><li>description</li><li>bgColor</li></ul><p>You can use whatever variables you want. The <code>ImageResponse</code> returns a <code>png</code> image. <code>satori</code> creates an <code>svg</code> and <code>sharp</code> is used to convert the image to a <code>png</code>.</p><h2 id="dynamic-images">Dynamic Images</h2><p>Because you can pass parameters, you can create on-the-fly images through the parameters.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span>html<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>head<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>meta
      property<span class="token operator">=</span><span class="token string">"og:image"</span>
      content<span class="token operator">=</span><span class="token string">"https://your-url.com/api/v1/og-images?title=Developer"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>meta
      name<span class="token operator">=</span><span class="token string">"twitter:image"</span>
      content<span class="token operator">=</span><span class="token string">"https://your-url.com/api/v1/og-images?title=Developer"</span>
      <span class="token keyword">key</span><span class="token operator">=</span><span class="token string">"twitter:image"</span>
    <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>head<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>html<span class="token operator">&gt;</span>
</code></pre><h2 id="demo">Demo</h2><p>For this example, I am generating several images from the same route. The default route has no parameters.</p><ul><li><code>/api/og-image</code></li><li><code>/api/og-image?title=&hellip;</code></li><li><code>/api/og-image?title=&hellip;&amp;description=</code></li></ul><p>You can also pass extra fields in the title or description fields like a span.</p><pre class=" language-sql"><code class="prism  language-sql">title<span class="token operator">=</span><span class="token operator">&lt;</span>span<span class="token operator">%</span>20class<span class="token operator">=</span><span class="token string">'text-red-300'</span><span class="token operator">&gt;</span>Kendo<span class="token operator">+</span>UI<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
</code></pre><p> Notice it is HTML encoded.</p><h3 id="request">Request</h3><p>Since we are generating the image URL first on the server, we need to get the correct URL from the <code>request</code> event. This is important so it can work on any server without changing the URL manually, including on the local machine.</p><p>Edit the <code>main.server.ts</code> file to get the <code>request</code> event through <code>provideServerContext</code>.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> <span class="token string">'zone.js/node'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token string">'@angular/platform-server/init'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { provideServerContext } <span class="token keyword">from</span> <span class="token string">'@analogjs/router/server'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> { AppComponent } <span class="token keyword">from</span> <span class="token string">'./app/app'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { config } <span class="token keyword">from</span> <span class="token string">'./app/app.config.server'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { renderApplication } <span class="token keyword">from</span> <span class="token string">'@angular/platform-server'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { bootstrapApplication<span class="token punctuation">,</span> BootstrapContext } <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ServerContext } <span class="token keyword">from</span> <span class="token string">'@analogjs/router/tokens'</span><span class="token punctuation">;</span>

export <span class="token keyword">function</span> bootstrap<span class="token punctuation">(</span>context: BootstrapContext<span class="token punctuation">)</span> {
  <span class="token keyword">return</span> bootstrapApplication<span class="token punctuation">(</span>AppComponent<span class="token punctuation">,</span> config<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
}

export <span class="token keyword">default</span> async <span class="token keyword">function</span> render<span class="token punctuation">(</span>
  url: string<span class="token punctuation">,</span>
  document: string<span class="token punctuation">,</span>
  serverContext: ServerContext<span class="token punctuation">,</span>
<span class="token punctuation">)</span> {
  const html <span class="token operator">=</span> await renderApplication<span class="token punctuation">(</span>bootstrap<span class="token punctuation">,</span> {
    document<span class="token punctuation">,</span>
    url<span class="token punctuation">,</span>
    platformProviders: <span class="token punctuation">[</span>provideServerContext<span class="token punctuation">(</span>serverContext<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  }<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> html<span class="token punctuation">;</span>
}
</code></pre><h3 id="config">Config</h3><p>Make sure to turn on <code>ssr</code> and turn off <code>static</code> in the <code>vite.config.ts</code> file.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token comment">/// &lt;reference types="vitest" /&gt;</span>

<span class="token keyword">import</span> { defineConfig } <span class="token keyword">from</span> <span class="token string">'vite'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> analog <span class="token keyword">from</span> <span class="token string">'@analogjs/platform'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> tailwindcss <span class="token keyword">from</span> <span class="token string">'@tailwindcss/vite'</span><span class="token punctuation">;</span>

<span class="token comment">// https://vitejs.dev/config/</span>
export <span class="token keyword">default</span> defineConfig<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">(</span>{
  build: {
    target: <span class="token punctuation">[</span><span class="token string">'es2020'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  }<span class="token punctuation">,</span>
  resolve: {
    mainFields: <span class="token punctuation">[</span><span class="token string">'module'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  }<span class="token punctuation">,</span>
  plugins: <span class="token punctuation">[</span>
    analog<span class="token punctuation">(</span>{
      ssr: <span class="token boolean">true</span><span class="token punctuation">,</span>
      static: <span class="token boolean">false</span><span class="token punctuation">,</span>
      prerender: {
        routes: <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      }<span class="token punctuation">,</span>
      nitro: {
        preset: <span class="token string">'vercel'</span>
      }
    }<span class="token punctuation">)</span><span class="token punctuation">,</span>
    tailwindcss<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
}<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>⚠️ This will NOT work in Bun, Deno, Vercel Edge Functions, nor Cloudflare. Standard Node environments and serverless functions only! Only the Next.js version will correctly compile the large WASM file necessary to convert the SVG to a PNG. Hopefully, the framework developers will get this working for those environments as well. There may be some hacks, but I have never personally succeeded to get it working.</p><h3 id="origin">Origin</h3><p>Next, we need to create a token to get the correct origin URL on the server and browser. I put this in <code>app/lib/utils.ts</code>.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { injectRequest } <span class="token keyword">from</span> <span class="token string">"@analogjs/router/tokens"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { isPlatformBrowser } <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { DOCUMENT<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> InjectionToken<span class="token punctuation">,</span> PLATFORM_ID } <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>

export const ORIGIN <span class="token operator">=</span> new InjectionToken<span class="token operator">&lt;</span>string<span class="token operator">&gt;</span><span class="token punctuation">(</span>
  <span class="token string">'origin'</span><span class="token punctuation">,</span>
  {
    providedIn: <span class="token string">'root'</span><span class="token punctuation">,</span>
    factory<span class="token punctuation">(</span><span class="token punctuation">)</span> {
      <span class="token comment">// You could hardcode this, or just hydrate the server value</span>
      <span class="token comment">// This shows you how to derive it dynamically</span>
      const doc <span class="token operator">=</span> inject<span class="token punctuation">(</span>DOCUMENT<span class="token punctuation">)</span><span class="token punctuation">;</span>
      const platformId <span class="token operator">=</span> inject<span class="token punctuation">(</span>PLATFORM_ID<span class="token punctuation">)</span><span class="token punctuation">;</span>
      const isBrowser <span class="token operator">=</span> isPlatformBrowser<span class="token punctuation">(</span>platformId<span class="token punctuation">)</span><span class="token punctuation">;</span>
      const request <span class="token operator">=</span> injectRequest<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      const host <span class="token operator">=</span> request?<span class="token punctuation">.</span>headers<span class="token punctuation">.</span>host<span class="token punctuation">;</span>
      const protocol <span class="token operator">=</span> host?<span class="token punctuation">.</span>includes<span class="token punctuation">(</span><span class="token string">'localhost'</span><span class="token punctuation">)</span> ? <span class="token string">'http'</span> : <span class="token string">'https'</span><span class="token punctuation">;</span>
      const origin <span class="token operator">=</span> <span class="token punctuation">`</span>${protocol}:<span class="token comment">//${host}`;</span>
      <span class="token keyword">return</span> isBrowser ? doc<span class="token punctuation">.</span>location<span class="token punctuation">.</span>origin : origin<span class="token punctuation">;</span>
    }
  }
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><code>referer</code> will get the origin from the <code>request</code> event on the server, but we must get rid of the extra <code>/</code> at the end with <code>slice</code>. The can inject a safely usable <code>DOCUMENT</code> token that will not error out on the server. Now we can get the correct base URL in any environment.</p><h2 id="creating-the-images">Creating the Images</h2><p>We inject the <code>ORIGIN</code> token to get the correct URL.</p><pre class=" language-sql"><code class="prism  language-sql"><span class="token keyword">import</span> { Component<span class="token punctuation">,</span> inject } <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { ORIGIN } <span class="token keyword">from</span> <span class="token string">'../lib/utils'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> { Meta } <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span>

<span class="token variable">@Component</span><span class="token punctuation">(</span>{
  selector: <span class="token string">'app-home'</span><span class="token punctuation">,</span>
  standalone: <span class="token boolean">true</span><span class="token punctuation">,</span>
  template: <span class="token punctuation">`</span>
  <span class="token operator">&lt;</span>main class<span class="token operator">=</span><span class="token string">"flex flex-col gap-5 items-center justify-center py-10"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>h2 class<span class="token operator">=</span><span class="token string">"text-6xl font-semibold"</span><span class="token operator">&gt;</span>AnalogJS<span class="token operator">&lt;</span><span class="token operator">/</span>h2<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>h3 class<span class="token operator">=</span><span class="token string">"text-4xl font-medium"</span><span class="token operator">&gt;</span>OG Image Generator<span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>

    <span class="token operator">&lt;</span>img <span class="token punctuation">[</span>src<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img1"</span> alt<span class="token operator">=</span><span class="token string">"Default OG Image"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"text-6xl font-semibold"</span><span class="token operator">&gt;</span><span class="token operator">or</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>

    <span class="token operator">&lt;</span>img <span class="token punctuation">[</span>src<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img2"</span> alt<span class="token operator">=</span><span class="token string">"Custom Title &amp; Description"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">div</span> class<span class="token operator">=</span><span class="token string">"text-6xl font-semibold"</span><span class="token operator">&gt;</span><span class="token operator">or</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token operator">div</span><span class="token operator">&gt;</span>

    <span class="token operator">&lt;</span>img <span class="token punctuation">[</span>src<span class="token punctuation">]</span><span class="token operator">=</span><span class="token string">"img3"</span> alt<span class="token operator">=</span><span class="token string">"Styled Title, Custom BG"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">/</span>main<span class="token operator">&gt;</span>
  <span class="token punctuation">`</span><span class="token punctuation">,</span>
}<span class="token punctuation">)</span>
export <span class="token keyword">default</span> class HomeComponent {

  readonly origin <span class="token operator">=</span> inject<span class="token punctuation">(</span>ORIGIN<span class="token punctuation">)</span><span class="token punctuation">;</span>
  readonly meta <span class="token operator">=</span> inject<span class="token punctuation">(</span>Meta<span class="token punctuation">)</span><span class="token punctuation">;</span>

  constructor<span class="token punctuation">(</span><span class="token punctuation">)</span> {
    this<span class="token punctuation">.</span>meta<span class="token punctuation">.</span>updateTag<span class="token punctuation">(</span>{
      name: <span class="token string">'og:image'</span><span class="token punctuation">,</span>
      content: this<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">'/api/og-image'</span>
    }<span class="token punctuation">)</span><span class="token punctuation">;</span>
  }

  img1 <span class="token operator">=</span> this<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">'/api/og-image'</span><span class="token punctuation">;</span>

  img2 <span class="token operator">=</span> this<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">'/api/og-image?title=My%20Custom%20Title&amp;description=My%20Custom%20Description'</span><span class="token punctuation">;</span>

  img3 <span class="token operator">=</span> this<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">"/api/og-image?title=&lt;span%20class='text-red-300'&gt;Kendo+UI&lt;/span&gt;&amp;description=For%20Angular&amp;bgColor=%23eb0249"</span><span class="token punctuation">;</span>
}
</code></pre><p>You can see our images are created dynamically from our server route <code>/api/og-image</code>.</p><p> We could have hard-coded the image URLs, but then they would not work automatically if we change servers or if we test on localhost.</p><h3 id="meta">Meta</h3><p>We use the <code>Meta</code> injection to update the meta tag dynamically.</p><pre class=" language-sql"><code class="prism  language-sql">this<span class="token punctuation">.</span>meta<span class="token punctuation">.</span>updateTag<span class="token punctuation">(</span>{
  name: <span class="token string">'og:image'</span><span class="token punctuation">,</span>
  content: this<span class="token punctuation">.</span>origin <span class="token operator">+</span> <span class="token string">'/api/og-image'</span>
}<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We could do something similar for any image URLs on the page.</p><p> If we updated the header after a <code>fetch</code> or a time consuming JS function, we would need to update the tag in a <a target="_blank" href="https://angular.dev/guide/routing/data-resolvers#">resolver</a>, or use <a target="_blank" href="https://angular.dev/api/core/PendingTasks">PendingTasks</a> to wait for the tag to be updated on the server before the server page is rendered.</p><h3 id="bonus-seo-tips">Bonus SEO Tips</h3><p>➕ If we want to have the best SEO, we should generate our images for the best image sizes by platform.</p><ul><li>og:image &ndash; 1200 x 620</li><li>twitter:image (use summary large) &ndash; 1600 x 900</li><li>JSON-LD &ndash; 1200 x 620, 1600 x 900, and 1000 x 1500 (for Pinterest)</li></ul><pre class=" language-sql"><code class="prism  language-sql"><span class="token operator">&lt;</span>head<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token comment">-- Primary Meta Tags --&gt;</span>
  <span class="token operator">&lt;</span>title<span class="token operator">&gt;</span>Example Page Title<span class="token operator">&lt;</span><span class="token operator">/</span>title<span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"description"</span> content<span class="token operator">=</span><span class="token string">"Short, compelling description for SEO."</span> <span class="token operator">/</span><span class="token operator">&gt;</span>

  <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token comment">-- Canonical URL --&gt;</span>
  <span class="token operator">&lt;</span>link rel<span class="token operator">=</span><span class="token string">"canonical"</span> href<span class="token operator">=</span><span class="token string">"https://example.com/your-page"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>

  <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token comment">-- Open Graph / Facebook --&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:type"</span> content<span class="token operator">=</span><span class="token string">"website"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:url"</span> content<span class="token operator">=</span><span class="token string">"https://example.com/your-page"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:title"</span> content<span class="token operator">=</span><span class="token string">"Example Page Title"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:description"</span> content<span class="token operator">=</span><span class="token string">"Short, compelling description for SEO."</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:image"</span> content<span class="token operator">=</span><span class="token string">"https://example.com/images/your-image-1200x630.jpg"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:image:width"</span> content<span class="token operator">=</span><span class="token string">"1200"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:image:height"</span> content<span class="token operator">=</span><span class="token string">"630"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta property<span class="token operator">=</span><span class="token string">"og:image:alt"</span> content<span class="token operator">=</span><span class="token string">"Descriptive alt text for your image."</span> <span class="token operator">/</span><span class="token operator">&gt;</span>

  <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token comment">-- Twitter --&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:card"</span> content<span class="token operator">=</span><span class="token string">"summary_large_image"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:url"</span> content<span class="token operator">=</span><span class="token string">"https://example.com/your-page"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:title"</span> content<span class="token operator">=</span><span class="token string">"Example Page Title"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:description"</span> content<span class="token operator">=</span><span class="token string">"Short, compelling description for SEO."</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:image"</span> content<span class="token operator">=</span><span class="token string">"https://example.com/images/your-image-1600x900.jpg"</span> <span class="token operator">/</span><span class="token operator">&gt;</span>
  <span class="token operator">&lt;</span>meta name<span class="token operator">=</span><span class="token string">"twitter:image:alt"</span> content<span class="token operator">=</span><span class="token string">"Descriptive alt text for your image."</span> <span class="token operator">/</span><span class="token operator">&gt;</span>

  <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token comment">-- JSON-LD Schema --&gt;</span>
  <span class="token operator">&lt;</span>script <span class="token keyword">type</span><span class="token operator">=</span><span class="token string">"application/ld+json"</span><span class="token operator">&gt;</span>
  {
    <span class="token string">"@context"</span>: <span class="token string">"https://schema.org"</span><span class="token punctuation">,</span>
    <span class="token string">"@type"</span>: <span class="token string">"WebPage"</span><span class="token punctuation">,</span>
    <span class="token string">"name"</span>: <span class="token string">"Example Page Title"</span><span class="token punctuation">,</span>
    <span class="token string">"description"</span>: <span class="token string">"Short, compelling description for SEO."</span><span class="token punctuation">,</span>
    <span class="token string">"url"</span>: <span class="token string">"https://example.com/your-page"</span><span class="token punctuation">,</span>
    <span class="token string">"image"</span>: <span class="token punctuation">[</span>
      <span class="token string">"https://example.com/images/your-image-1200x630.jpg"</span><span class="token punctuation">,</span>
      <span class="token string">"https://example.com/images/your-image-1600x900.jpg"</span><span class="token punctuation">,</span>
      <span class="token string">"https://example.com/images/your-image-1000x1500.jpg"</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token string">"author"</span>: {
      <span class="token string">"@type"</span>: <span class="token string">"Person"</span><span class="token punctuation">,</span>
      <span class="token string">"name"</span>: <span class="token string">"John Doe"</span>
    }<span class="token punctuation">,</span>
    <span class="token string">"publisher"</span>: {
      <span class="token string">"@type"</span>: <span class="token string">"Organization"</span><span class="token punctuation">,</span>
      <span class="token string">"name"</span>: <span class="token string">"Example Company"</span><span class="token punctuation">,</span>
      <span class="token string">"logo"</span>: {
        <span class="token string">"@type"</span>: <span class="token string">"ImageObject"</span><span class="token punctuation">,</span>
        <span class="token string">"url"</span>: <span class="token string">"https://example.com/images/logo-512x512.png"</span>
      }
    }
  }
  <span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">&gt;</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>head<span class="token operator">&gt;</span>
</code></pre><p> You don&rsquo;t need to specify the image sizes in JSON-LD.</p><h2 id="result">Result</h2><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image.png?sfvrsn=add6a6c9_2" alt="Green background with words Progress Telerik Kendo UI" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image-1.png?sfvrsn=f41aebc4_2" alt="Green background with text: My Custom Title / My Custom Description" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image-2.png?sfvrsn=b46e1674_2" alt="Red background with text: Kendo UI For Angular" /></p><h2 id="testing-og-image">Testing OG Image</h2><p>When we test our URL on <a target="_blank" href="https://www.opengraph.xyz/">Open Graph XYZ</a>, we can see it works! Using a plain <code>og:image</code> tag is a minimum for most use cases.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/screenshot_2025-10-19_203010.png?sfvrsn=a3983d90_2" alt="screenshot of images sized for Facebook and X / Twitter" /></p><p><strong>Repo:</strong> <a target="_blank" href="https://github.com/jdgamble555/analog-og-image">GitHub</a><br /><strong>Demo:</strong> <a target="_blank" href="https://analog-og-image.vercel.app/">Vercel Functions</a></p><p>Beautiful dynamic images ready to be used as your preview image.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Build Agentic Apps with Angular, Genkit and Kendo UI</h4></div><div class="col-8"><p class="u-fs16 u-mb0">Get started on an <a target="_blank" href="https://www.telerik.com/blogs/build-agentic-apps-angular-genkit-kendo-ui-part-1">agentic Angular app with Genkit and Gemini</a>. We&rsquo;ll build out the ability for users to ask about the status of their order.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17263760.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:47b45041-6ce2-4cad-88ea-10d4eaa997fb</id>
    <title type="text">Build Agentic Apps with Angular, Genkit and Kendo UI: Part 2</title>
    <summary type="text">Let’s build out the Angular app for our Genkit backend, so users can ask about their order status and get an AI-empowered answer.</summary>
    <published>2026-01-20T17:05:23Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17258644/build-agentic-apps-angular-genkit-kendo-ui-part-2"/>
    <content type="text"><![CDATA[<p><span class="featured">Let&rsquo;s build out the Angular app for our Genkit backend, so users can ask about their order status and get an AI-empowered answer.</span></p><p>In <a href="https://www.telerik.com/blogs/build-agentic-apps-angular-genkit-kendo-ui-part-1" target="_blank">Part 1 of this series</a>, we built our first agentic app with Genkit. We created flows, connected a status-check tool that uses Gemini, and tested everything with the <a target="_blank" href="https://genkit.dev/docs/devtools/#genkit-developer-ui">Genkit Developer UI</a>.</p><p>The Developer UI is very useful for testing and debugging. For example, <code>orderSupportFlow</code> automatically called <code>getOrderStatusTool</code> when we asked &ldquo;Where is my order 123-456?&rdquo;</p><p>I want to be honest: our users can&rsquo;t exactly visit <code>http://localhost:4001</code> to check their order status, right? They need a beautiful, production-ready interface they can actually use.</p><p>AI is powerful, but it needs other technologies around it to deliver value. AI alone cannot interact with people; the rest of the stack must handle that job.</p><p>Today we will build an Angular chat application that talks to our Genkit backend. The goal is to deliver something simple and friendly for end users.</p><h2 id="from-genkit-developer-ui-to-angular-and-kendo-ui-">From Genkit Developer UI to Angular and Kendo UI </h2><p>Our goal is to build a clear chat interface with Angular. The interface will call our existing Genkit backend through a simple API layer, so the frontend and backend can communicate without special tricks.</p><p>This may sound complex, but the hard parts are already done because the agentic backend is ready. We only need to add a user interface.</p><p>We want to reach the following goals:</p><ul><li>A clean, intuitive chat interface</li><li>The ability to ask questions in natural language</li><li>Instant responses that feel conversational</li></ul><p>How do we take our working Genkit backend and connect it to a real Angular application with a delightful chat experience?</p><p>We will reuse the existing backend (with <code>orderSupportFlow</code> and <code>getOrderStatusTool</code>) and expose it through an Express REST API. Angular will call this API, so we do not need to change the AI logic.</p><p>Express acts as the bridge. It converts HTTP requests into Genkit flow calls that already work.</p><p>Instead of running <code>orderSupportFlow("What's my order status for 123-456?")</code> manually, we&rsquo;ll hit an endpoint like:</p><pre class=" language-typescript"><code class="prism  language-typescript">POST <span class="token operator">/</span>api<span class="token operator">/</span>order<span class="token operator">-</span>flow
<span class="token punctuation">{</span>
  <span class="token string">"data"</span><span class="token punctuation">:</span> <span class="token string">"What's my order status for 123-456?"</span>
<span class="token punctuation">}</span>
</code></pre><p>Think of Express as a translator between the smart Genkit backend and the Angular frontend:</p><ul><li><strong>Genkit flows</strong> stay exactly the same (no need to change our code!).</li><li><strong>Express.js</strong> acts as the translator, converting HTTP requests into Genkit flow calls.</li><li><strong>Angular</strong> gets clean REST endpoints it knows how to use.</li></ul><p>This approach keeps the agentic logic isolated. Any frontend (Angular, React, Vue and so on) can call the same APIs.</p><p>Let&rsquo;s start building the bridge.</p><h2 id="setting-up-the-project">Setting Up the Project</h2><p>First, be sure to clone the repo and install the dependencies with <code>npm i</code> into the <code>agentic-app/backend</code> directory:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">git</span> clone https://github.com/danywalls/agentic-app.git
<span class="token function">cd</span> agentic-app/backend
<span class="token function">npm</span> i
</code></pre><p>Open the project in your editor and head to <code>backend/src/</code>. Rename <code>index.ts</code> (which currently holds the Genkit logic) to <code>genkit.ts</code>.</p><blockquote><p>Whenever you add a new AI flow, you&rsquo;ll only need to touch <code>genkit.ts</code>.</p></blockquote><p>Your <code>genkit.ts</code> is now complete! Notice how it only knows about AI; it&rsquo;s just pure Genkit logic, so it&rsquo;s time to create our REST API quickly using Express.</p><h2 id="express-server">Express Server</h2><p>Express.js is a minimalist web framework for Node.js that makes it easy to build web servers and APIs by handling most HTTP plumbing for you.</p><blockquote><p>Need a refresher? Check out the <strong><a target="_blank" href="https://expressjs.com/en/starter/installing.html">Express.js Official Guide</a></strong>.</p></blockquote><p>From the <code>backend</code> directory, install the dependencies we&rsquo;ll need:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> express body-parser cors @types/cors
</code></pre><p>Create a new entry file at <code>backend/src/server.ts</code>:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">touch</span> src/server.ts
</code></pre><p>Copy the following snippet, which creates an Express server at port 3000. After it starts, it shows <code>Server running on port 3000</code>. We have the default route <code>/</code> returning a nice message <code>Genkit with Express</code> using the <code>res.send</code> method.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> express <span class="token keyword">from</span> <span class="token string">"express"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> bodyParser <span class="token keyword">from</span> <span class="token string">"body-parser"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> cors <span class="token keyword">from</span> <span class="token string">"cors"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> jsonParser <span class="token operator">=</span> bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> PORT <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>PORT <span class="token operator">||</span> <span class="token number">3000</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">cors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>_req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">"Genkit with Express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>PORT<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Server running on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>PORT<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Run it with:</p><pre class=" language-bash"><code class="prism  language-bash">npx tsx src/server.ts
</code></pre><p>You should see &ldquo;Server running on port 3000&rdquo; in the terminal and the message &ldquo;Genkit with Express&rdquo; when visiting <code>http://localhost:3000</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/genkit-express.png?sfvrsn=c5d23c13_2" alt="Genkit with Express" /></p><p>Perfect, so let&rsquo;s move to the next step: exposing an endpoint that forwards chat prompts to <code>orderSupportFlow</code>. Because the Angular client will send JSON payloads, keep <code>jsonParser</code> in place and wrap the async handler in a <code>try/catch</code>:</p><pre class=" language-typescript"><code class="prism  language-typescript">app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"/order-flow"</span><span class="token punctuation">,</span> jsonParser<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">orderSupportFlow</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">"Something went wrong"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote><p>If your editor auto-imports <code>orderSupportFlow</code> with a <code>.js</code> extension, update <code>tsconfig.json</code> with:</p></blockquote><pre class=" language-json"><code class="prism  language-json"><span class="token string">"moduleResolution"</span><span class="token punctuation">:</span> <span class="token string">"bundler"</span><span class="token punctuation">,</span>
<span class="token string">"module"</span><span class="token punctuation">:</span> <span class="token string">"esnext"</span>
</code></pre><p>This tells TypeScript (and <code>tsx</code>) to resolve modern ESM modules without forcing <code>.js</code> extensions.</p><p>The final code looks:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> express <span class="token keyword">from</span> <span class="token string">"express"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> bodyParser <span class="token keyword">from</span> <span class="token string">"body-parser"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> cors <span class="token keyword">from</span> <span class="token string">"cors"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> orderSupportFlow <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./genkit"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> jsonParser <span class="token operator">=</span> bodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> PORT <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>PORT <span class="token operator">||</span> <span class="token number">3000</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">cors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>_req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">"Genkit with Express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"/order-flow"</span><span class="token punctuation">,</span> jsonParser<span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">orderSupportFlow</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">"Something went wrong"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>PORT<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Server running on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>PORT<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote><p>Remember: To get an API key, visit <a target="_blank" href="https://aistudio.google.com/apikey">https://aistudio.google.com/apikey</a>, sign in with your Google account and create an API key and update <code>GEMINI_API_KEY=</code> into the <code>.env</code> file.</p></blockquote><p>With everything in place, we can shift to Angular and Kendo UI to post messages to <code>/order-flow</code> and display the responses in a chat UI.</p><h2 id="angular-and-conversational-kendo-ui">Angular and Conversational Kendo UI</h2><p>First, we make sure you have the latest Angular CLI:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g @angular/cli
</code></pre><p>From the repo root workspace <code>agentic-app</code> directory, create a new Angular application by using the CLI:</p><pre class=" language-bash"><code class="prism  language-bash">ng new genkit-frontend
</code></pre><p>Accept the default configuration. When the CLI finishes, move into the directory <code>genkit-frontend</code>:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">cd</span> genkit-frontend
</code></pre><p>We start by generating environment files so we can store the API base URL:</p><pre class=" language-bash"><code class="prism  language-bash">ng g environments
</code></pre><p>Update <code>src/environments/environment.development.ts</code> to point to our API <code>http://localhost:3000</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">const</span> environment <span class="token operator">=</span> <span class="token punctuation">{</span>
  API<span class="token punctuation">:</span> <span class="token string">"http://localhost:3000"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Next, let&rsquo;s install the <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/conversational-ui">Angular Conversational UI component</a> from Progress Kendo UI for Angular. Using the schematics <code>ng add</code>, its configuration and setup of everything related to Kendo UI is easy.</p><pre class=" language-bash"><code class="prism  language-bash">ng add @progress/kendo-angular-conversational-ui
</code></pre><p>With the dependencies installed, we can build the chatbot experience using Conversational UI! </p><h2 id="the-chat-with-conversational-ui">The Chat with Conversational UI</h2><p>Before we start, let&rsquo;s clarify some aspects. When we think about a chat, it&rsquo;s an interaction between two users, in this case, the bot and the user. They interact via messages with an action or event in the chat.</p><p>As you&rsquo;ve seen, adding a few entities, types and an event inside a conversation sounds like hard work if we want to build it in safe mode with types. But don&rsquo;t worry! Conversational UI brings with it built-in types and the <code>kendo-chat</code> component provides props like <code>messages</code>, events like <code>sendMessage</code> and <code>authorId</code> to know who&rsquo;s sending the messages.</p><p>Create <code>src/app/entities/models.ts</code> to define the two participants:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> User <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@progress/kendo-angular-conversational-ui"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> BOT<span class="token punctuation">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"Agent"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> USER<span class="token punctuation">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token string">"You"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Next, generate a service that will handle chat state and API calls:</p><pre class=" language-bash"><code class="prism  language-bash">ng g s services/genkit
</code></pre><p>Inject <code>HttpClient</code>, to make the request and declare a public <code>messages</code> signal of type <code>Message[]</code> and seed the conversation with a greeting from the bot:</p><pre class=" language-typescript"><code class="prism  language-typescript">@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span> providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">GenkitService</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> http <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>HttpClient<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">public</span> messages <span class="token operator">=</span> signal<span class="token operator">&lt;</span>Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
      text<span class="token punctuation">:</span> <span class="token string">"Hello! Ask me about order status (e.g., order 123-456)."</span><span class="token punctuation">,</span>
      timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Create the <code>sendMessage</code> method so it updates the user&rsquo;s message, calls the Express endpoint, and pushes the bot&rsquo;s response (or an error message) back into the stream:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">public</span> <span class="token function">sendMessage</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> userMessage<span class="token punctuation">:</span> Message <span class="token operator">=</span> <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      author<span class="token punctuation">:</span> USER<span class="token punctuation">,</span>
      text<span class="token punctuation">,</span>
      timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>current<span class="token punctuation">,</span> userMessage<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> payload <span class="token operator">=</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> text <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>environment<span class="token punctuation">.</span>API<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/order-flow`</span></span><span class="token punctuation">,</span> payload<span class="token punctuation">,</span> <span class="token punctuation">{</span> responseType<span class="token punctuation">:</span> <span class="token string">'text'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
        <span class="token function">catchError</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>

          <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>current<span class="token punctuation">,</span> <span class="token punctuation">{</span>
            id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
            text<span class="token punctuation">:</span> <span class="token string">'Sorry, I encountered an error. Please try again.'</span><span class="token punctuation">,</span>
            timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">return</span> EMPTY<span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>current<span class="token punctuation">,</span> <span class="token punctuation">{</span>
          id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
          text<span class="token punctuation">:</span> response <span class="token operator">||</span> <span class="token string">'No response received'</span><span class="token punctuation">,</span>
          timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>The final code looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> signal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> HttpClient <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common/http"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Message <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@progress/kendo-angular-conversational-ui"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> catchError <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rxjs/operators"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> EMPTY <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rxjs"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> BOT<span class="token punctuation">,</span> USER <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../entities/models"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> environment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../environments/environment"</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span> providedIn<span class="token punctuation">:</span> <span class="token string">"root"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">GenkitService</span> <span class="token punctuation">{</span>
  <span class="token keyword">private</span> http <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>HttpClient<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">public</span> messages <span class="token operator">=</span> signal<span class="token operator">&lt;</span>Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
      text<span class="token punctuation">:</span> <span class="token string">"Hello! Ask me about order status (e.g., order 123-456)."</span><span class="token punctuation">,</span>
      timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">public</span> <span class="token function">sendMessage</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> userMessage<span class="token punctuation">:</span> Message <span class="token operator">=</span> <span class="token punctuation">{</span>
      id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      author<span class="token punctuation">:</span> USER<span class="token punctuation">,</span>
      text<span class="token punctuation">,</span>
      timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>current<span class="token punctuation">,</span> userMessage<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> payload <span class="token operator">=</span> <span class="token punctuation">{</span> data<span class="token punctuation">:</span> text <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>http
      <span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>environment<span class="token punctuation">.</span>API<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/order-flow`</span></span><span class="token punctuation">,</span> payload<span class="token punctuation">,</span> <span class="token punctuation">{</span> responseType<span class="token punctuation">:</span> <span class="token string">"text"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
        <span class="token function">catchError</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
            <span class="token operator">...</span>current<span class="token punctuation">,</span>
            <span class="token punctuation">{</span>
              id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
              author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
              text<span class="token punctuation">:</span> <span class="token string">"Sorry, I encountered an error. Please try again."</span><span class="token punctuation">,</span>
              timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

          <span class="token keyword">return</span> EMPTY<span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">(</span>response<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>messages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">(</span>current<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
          <span class="token operator">...</span>current<span class="token punctuation">,</span>
          <span class="token punctuation">{</span>
            id<span class="token punctuation">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            author<span class="token punctuation">:</span> BOT<span class="token punctuation">,</span>
            text<span class="token punctuation">:</span> response <span class="token operator">||</span> <span class="token string">"No response received"</span><span class="token punctuation">,</span>
            timestamp<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>We have our service ready! Let&rsquo;s move to the final step: connecting all the service pieces with the Conversational UI component!</p><h2 id="the-conversational-ui-component">The Conversational UI Component</h2><p>Now let&rsquo;s plug the service into the UI. Open <code>app.ts</code> and import <code>KENDO_CONVERSATIONALUI</code> into the imports sections and inject the genkitService to expose the current user and read the reactive <code>messages</code> signal.</p><p>These properties will bind the <code>kendo-chat</code> component from the template properties later.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> KENDO_CONVERSATIONALUI<span class="token punctuation">,</span> SendMessageEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@progress/kendo-angular-conversational-ui'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> GenkitService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./services/genkit'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> USER <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./entities/models'</span><span class="token punctuation">;</span>


@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-root'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_CONVERSATIONALUI<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./app.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./app.css'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>

  genkitService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>GenkitService<span class="token punctuation">)</span><span class="token punctuation">;</span>
  user <span class="token operator">=</span> USER<span class="token punctuation">;</span>
  messages <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>genkitService<span class="token punctuation">.</span>messages<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>The kendo-chat component fires a <code>SendMessageEvent</code> every time someone hits Enter or taps the send icon. All we need to do is grab the text, make sure it is not empty, and use <code>sendMessage</code> from the genkitService to update the signals and the UI and call the API.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">public</span> <span class="token function">onSendMessage</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> SendMessageEvent<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> messageText <span class="token operator">=</span> event<span class="token punctuation">.</span>message<span class="token punctuation">.</span>text <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">""</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>messageText<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>genkitService<span class="token punctuation">.</span><span class="token function">sendMessage</span><span class="token punctuation">(</span>messageText<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>The final code looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> inject <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  KENDO_CONVERSATIONALUI<span class="token punctuation">,</span>
  SendMessageEvent<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@progress/kendo-angular-conversational-ui"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> GenkitService <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./services/genkit"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> USER <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./entities/models"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">"app-root"</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>KENDO_CONVERSATIONALUI<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">"./app.html"</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">"./app.css"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
  genkitService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>GenkitService<span class="token punctuation">)</span><span class="token punctuation">;</span>
  user <span class="token operator">=</span> USER<span class="token punctuation">;</span>
  messages <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>genkitService<span class="token punctuation">.</span>messages<span class="token punctuation">;</span>

  <span class="token keyword">public</span> <span class="token function">onSendMessage</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span> SendMessageEvent<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> messageText <span class="token operator">=</span> event<span class="token punctuation">.</span>message<span class="token punctuation">.</span>text <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">""</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>messageText<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>genkitService<span class="token punctuation">.</span><span class="token function">sendMessage</span><span class="token punctuation">(</span>messageText<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><blockquote><p>And don&rsquo;t forget to give <a href="https://www.telerik.com/try/kendo-angular-ui" target="_blank">Kendo UI for Angular a try</a> (for free) if you haven&rsquo;t already! (No credit card required!)</p></blockquote><p>Now, the final step is to update the app.html (the template), remove the default boilerplate and add the <code>&lt;kendo-chat&gt;</code> component and pass three things to <code>&lt;kendo-chat&gt;</code>:</p><p>Let&rsquo;s have a small overview about kendo-chat. I will give a little overview of the key properties to make it easy for us:</p><ul><li><code>[messages]</code>: Binds the messages array from the current conversation to the chat component.</li><li><code>[user]</code>: Defines the current user interacting with the chat. This is important for differentiating between messages sent by the user and others.</li><li><code>(sendMessage)</code>: Event emitted when user hits send.</li></ul><blockquote><p>Read more about <a target="_blank" href="https://www.telerik.com/kendo-angular-ui/components/conversational-ui">Conversational UI</a>.</p></blockquote><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>chat-container<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>My Angular Agentic App<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>kendo-chat</span>
    <span class="token attr-name">[messages]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>messages()<span class="token punctuation">"</span></span>
    <span class="token attr-name">[authorId]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user.id<span class="token punctuation">"</span></span>
    <span class="token attr-name">(sendMessage)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>onSendMessage($event)<span class="token punctuation">"</span></span>
  <span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>kendo-chat</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Perfect! We are done, and it&rsquo;s time to test our code. But before we continue, instead of starting the ng server and the api manually every time, first create a package.json by running the following command:</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> init -y
</code></pre><p>Next, add helper scripts <code>package.json</code> to both servers to start with one command:</p><pre class=" language-json"><code class="prism  language-json"><span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
  <span class="token string">"start"</span><span class="token punctuation">:</span> <span class="token string">"npm run backend &amp; npm run frontend"</span><span class="token punctuation">,</span>
  <span class="token string">"backend"</span><span class="token punctuation">:</span> <span class="token string">"cd backend &amp;&amp; npm run dev"</span><span class="token punctuation">,</span>
  <span class="token string">"frontend"</span><span class="token punctuation">:</span> <span class="token string">"cd genkit-frontend &amp;&amp; ng serve"</span>
<span class="token punctuation">}</span>
</code></pre><p>Run <code>npm run start</code> and open <code>http://localhost:4200</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/agentic-app-angular.gif?sfvrsn=c62604de_2" alt="My Agentic Angular App. User asks where order is. Agent responds with status and expected delivery date" /></p><p>Yeahhh! Done!! We have our Genkit Agent connected with the users thanks to Express, Angular and Kendo UI!!!</p><h2 id="what-we-accomplished">What We Accomplished</h2><p>We connected <a target="_blank" href="https://firebase.google.com/docs/genkit">Google&rsquo;s Genkit</a> AI flows to an Angular application. Genkit keeps the AI work, Angular with signals runs the frontend, and <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Kendo UI for Angular</a> provides the chat interface with a small amount of code.</p><p>The result is amazing! The AI logic, API code and UI code stay in separate places. Now you have the freedom to create new workflows, new endpoints and of course use more Kendo UI components in your amazing product!</p><p><a target="_blank" href="https://github.com/danywalls/agentic-app">Source Code Initial.</a><br /><a target="_blank" href="https://github.com/danywalls/agentic-app/tree/final">Source Code Final.</a></p><h3 id="ready-to-try-kendo-ui-for-angular">Ready to Try Kendo UI for Angular?</h3><p>To explore all the components available in the Kendo UI for Angular library, I recommend you download the free 30-day trial and explore it for yourself!</p><p><a href="https://www.telerik.com/try/kendo-angular-ui" target="_blank" class="Btn">Try Now</a></p><img src="https://feeds.telerik.com/link/23055/17258644.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:61911a49-92de-4e78-a46b-3e94e66c6fec</id>
    <title type="text">Build Agentic Apps with Angular, Genkit and Kendo UI: Part 1</title>
    <summary type="text">Get started on an agentic Angular app with Genkit and Gemini. We’ll build out the ability for users to ask about the status of their order.</summary>
    <published>2026-01-13T18:03:12Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17252636/build-agentic-apps-angular-genkit-kendo-ui-part-1"/>
    <content type="text"><![CDATA[<p><span class="featured">Get started on an agentic Angular app with Genkit and Gemini. We&rsquo;ll build out the ability for users to ask about the status of their order.</span></p><p>Chatbots and AI are in practically every sentence that comes out of our mouths. Most websites come with a chatbot providing answers to customers connected with an LLM that answers questions using its vast knowledge base. </p><p>For example, we created a nice <a target="_blank" href="https://www.telerik.com/blogs/build-chatlens-kendo-ui-gemini-angular-19">Chatbot using Gemini</a> that can recommend which Progress Kendo UI for <a target="_blank" href="https://www.telerik.com/kendo-angular-ui">Angular components</a> to use to build a webpage based on an image input. This chatbot works fine, because Gemini uses its trained data to answer, but what happens when we want a chatbot that answers something not related to its training data?</p><p>If you ask something like &ldquo;check my order status&rdquo;? It hits a wall. The LLM doesn&rsquo;t have that knowledge, and this is the moment where an agent can help us, and when we need to move on to talk about agentic apps.</p><p>An agentic app is like a smart assistant that not only answers questions but can also utilize tools to complete tasks. It can reason, plan and interact with other systems.</p><p>This sounds a bit complex, but don&rsquo;t worry: this is when <a target="_blank" href="https://genkit.dev/">Genkit</a> comes to the game, to help us create agentic apps with ease.</p><p>Today we&rsquo;ll build a complete, working application from scratch. Starting with Genkit, we&rsquo;ll create an agent that can check an order status using the power of Gemini and Genkit.</p><p>Let&rsquo;s move on!</p><h2 id="what-is-genkit-flows-and-tools-">What Is Genkit? Flows and Tools? </h2><p>Before we start typing code, let&rsquo;s take a step back. We need to understand what Genkit is, plus its flows and tools. By using a real-world example we all know, Amazon customer support, this will make everything super clear.</p><h3 id="what-is-genkit">What Is Genkit?</h3><p>Think of Genkit as the &ldquo;brain&rdquo; behind the Amazon customer support system. It&rsquo;s like Angular for us, allowing us to build apps; Genkit is the entire framework that allows a developer to build the complete system. It&rsquo;s not the agent itself; it&rsquo;s the infrastructure that lets you create and manage all the processes and tools the agent will use.</p><p>In short, Genkit is the toolbox that helps us to build powerful AI applications.</p><h3 id="what-are-genkit-flows">What Are Genkit Flows?</h3><p>Imagine you need help with a lost package. You open the chat, and a new support session starts.</p><p>That entire process, from the moment you ask &ldquo;Where&rsquo;s my order?&rdquo; to the final resolution where you get a new tracking number or a refund, is a flow.</p><p>A flow is the main task or conversation you want to handle. It has the TypeScript functions like <code>checkOrderStatusFlow</code> or <code>processRefundFlow</code> and orchestrates the entire experience.</p><p>OK, we know Genkit and flows, but what is a tool ?</p><h3 id="what-are-genkit-tools-️">What Are Genkit Tools? ️</h3><p>If we go back to thinking about how the Amazon support agent works, it doesn&rsquo;t just magically know your order details. It uses tools internal to Amazon.</p><p>For example, we can provide an action called &ldquo;Look Up Order in Database&rdquo; or &ldquo;Send a New Tracking Number.&rdquo; Each of these is a tool.</p><p>A tool is a specific action the AI can perform. When a user asks about their order, the AI sees that its <code>checkOrderStatus</code> tool is perfect for the job. It understands what the tool does by reading its description, and then it knows when to use it to solve the problem.</p><h3 id="how-do-they-work-together">How Do They Work Together?</h3><p>Let&rsquo;s connect the dots. First, the flow is the entire conversation, the big picture. The tools are the small, powerful actions the AI can use to complete that conversation. And Genkit is the framework that lets you build and connect all of this together.</p><p>So, when you build a new Genkit app, you first create the flow (the main objective), and then you give it a set of tools (the specific capabilities) it can use to get the job done.</p><p>Now that we know about each part, let&rsquo;s build our first agent using Genkit!</p><h2 id="setting-up-the-project">Setting Up the Project</h2><p>Let&rsquo;s start by building our backend. This will be a Node.js server that exposes an API.</p><p>First, make sure you have <a target="_blank" href="https://nodejs.org/">Node.js</a> (v20+) installed, open your terminal and install the Genkit CLI.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g genkit-cli
</code></pre><p>Now, let&rsquo;s create our project folder for the whole project <code>my-agentic-app</code> and create the <code>backend</code> folder and navigate into it</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">mkdir</span> my-agentic-app
<span class="token function">cd</span> my-agentic-app
<span class="token function">mkdir</span> backend
<span class="token function">cd</span> backend
</code></pre><p>Next, we&rsquo;ll install the Genkit packages we need, but first initialize the project by running <code>npm init -y</code> and install the genkit, google-ai and zod packages.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> genkit @genkit-ai/google-genai
</code></pre><p>Let&rsquo;s give a small overview about them:</p><ul><li><code>genkit</code>: The core Genkit framework for building agentic apps</li><li><code>@google-genkit/google-ai</code>: The plugin for connecting to Gemini models</li><li><code>zod</code>: A library for defining data schemas, which Genkit uses for tools</li></ul><p>Last but not least, we use our favorite language, <a target="_blank" href="https://www.typescriptlang.org/download/">TypeScript</a>, so let&rsquo;s install TypeScript and <a target="_blank" href="https://tsx.is/">tsx</a> <code>npm install -D typescript tsx</code> and create the configuration running <code>npx tsc --init</code></p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">npm</span> <span class="token function">install</span> -D typescript tsx
npx tsc --init
</code></pre><p>Ok, it&rsquo;s time to write code!</p><h2 id="setting-up-our-agents-brain-">Setting Up Our Agent&rsquo;s Brain </h2><p>Now with our project ready and the full picture of Genkit, Flows and Tools, let&rsquo;s bring it to life! Remember our Amazon chatbot? It&rsquo;s time to build the agentic app.</p><p>First things first, let&rsquo;s create our project structure. Open your terminal and run these two simple commands to create a folder and index.ts file.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">mkdir</span> src
<span class="token function">touch</span> src/index.ts
</code></pre><p>Now, open <code>src/index.ts</code>. This is where all the magic starts. We will set up our Genkit instance, telling it which AI model to use. It&rsquo;s like the main engine that will power our entire application.</p><p>First import the <code>genkit, z</code> from the Genkit package and import googleAI from <code>@genkit-ai/google-genai</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> genkit<span class="token punctuation">,</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'genkit'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> googleAI <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@genkit-ai/google-genai'</span><span class="token punctuation">;</span>
</code></pre><p>Next, register the Google AI plugin <code>googleAI()</code> and tell the agent which specific brain (model) to use. We will be using the &lsquo;gemini-2.5-flash&rsquo; model and the temperature to the model.</p><blockquote><p>The temperature in models with a higher value means more creative, a lower value is more direct. <a target="_blank" href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/adjust-parameter-values">Learn more.</a></p></blockquote><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> ai <span class="token operator">=</span> <span class="token function">genkit</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">googleAI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  model<span class="token punctuation">:</span> googleAI<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span><span class="token string">'gemini-2.5-flash'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    temperature<span class="token punctuation">:</span> <span class="token number">0.8</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The final index.ts looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> genkit<span class="token punctuation">,</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'genkit'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> googleAI <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@genkit-ai/google-genai'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> ai <span class="token operator">=</span> <span class="token function">genkit</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">googleAI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  model<span class="token punctuation">:</span> googleAI<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span><span class="token string">'gemini-2.5-flash'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    temperature<span class="token punctuation">:</span> <span class="token number">0.8</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Ok, let&rsquo;s move to the tool!</p><h2 id="building-the-tool">Building the Tool ️</h2><p>What can our smart agent do? This is where a tool comes in! It&rsquo;s a specific, controlled action. Our agent will read the description of this tool and decide if it&rsquo;s the right one to use based on the user&rsquo;s question.</p><p>In this case, we&rsquo;re giving our agent the ability to check the status of an order. We tell it exactly what information it needs (for example the <code>orderId</code>) and what kind of information it will return (like <code>status</code> or <code>estimatedDelivery</code>).</p><blockquote><p>Note: The description is super important! The AI model uses this to know when to call the tool.</p></blockquote><p>Let&rsquo;s create a tool using the <code>ai.defineTool</code> function to define what information the tool needs to run and what kind of data the tool returns using zod (z).</p><p>For example, we&rsquo;ll create <code>getOrderStatusTool</code>. This is the actual function that runs when the tool is called. For our demo, we just check for a hardcoded ID to keep it simple, and if the ID isn&rsquo;t found, we return a clear status.</p><p>Check out the code:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">const</span> getOrderStatusTool <span class="token operator">=</span> ai<span class="token punctuation">.</span><span class="token function">defineTool</span><span class="token punctuation">(</span>
  <span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">'getOrderStatus'</span><span class="token punctuation">,</span>

    description<span class="token punctuation">:</span> <span class="token string">"Get the status of a user's order by their order ID."</span><span class="token punctuation">,</span>
  
    inputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      orderId<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"The unique ID of the customer's order"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
   
    outputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      status<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      estimatedDelivery<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token keyword">async</span> <span class="token punctuation">(</span>input<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>input<span class="token punctuation">.</span>orderId <span class="token operator">===</span> <span class="token string">'123-456'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">'Shipped'</span><span class="token punctuation">,</span> estimatedDelivery<span class="token punctuation">:</span> <span class="token string">'October 9, 2025'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
    <span class="token keyword">return</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">'Not Found'</span><span class="token punctuation">,</span> estimatedDelivery<span class="token punctuation">:</span> <span class="token string">'N/A'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote><p>Learn more about define tools with <a target="_blank" href="https://genkit.dev/docs/tool-calling/">Genkit</a>.</p></blockquote><h2 id="creating-the-workflow">Creating the Workflow</h2><p>The flow is the final piece. It is the main process that takes the user&rsquo;s prompt (the question) and hands it off to the AI model.</p><p>But here&rsquo;s where the magic happens: we pass a list of tools that the model is allowed to use.</p><p>The model (Gemini or wherever) is smart enough to read the user&rsquo;s prompt and decide if our <code>getOrderStatusTool</code> is the best way to answer. If it is, Genkit will automatically call that function for us!</p><p>This keeps our agent safe and predictable, because we can control exactly what actions it can perform.</p><p>Let&rsquo;s make this work in our project!</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">const</span> orderSupportFlow <span class="token operator">=</span> ai<span class="token punctuation">.</span><span class="token function">defineFlow</span><span class="token punctuation">(</span>
  <span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">'orderSupportFlow'</span><span class="token punctuation">,</span>
    inputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    outputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token keyword">async</span> <span class="token punctuation">(</span>prompt<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> llmResponse <span class="token operator">=</span> <span class="token keyword">await</span> ai<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      prompt<span class="token punctuation">:</span> prompt<span class="token punctuation">,</span>
      tools<span class="token punctuation">:</span> <span class="token punctuation">[</span>getOrderStatusTool<span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> llmResponse<span class="token punctuation">.</span>text<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The final code looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> genkit<span class="token punctuation">,</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"genkit"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> googleAI <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@genkit-ai/google-genai"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> ai <span class="token operator">=</span> <span class="token function">genkit</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
 plugins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token function">googleAI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
 model<span class="token punctuation">:</span> googleAI<span class="token punctuation">.</span><span class="token function">model</span><span class="token punctuation">(</span><span class="token string">"gemini-2.5-flash"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
   temperature<span class="token punctuation">:</span> <span class="token number">0.8</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> getOrderStatusTool <span class="token operator">=</span> ai<span class="token punctuation">.</span><span class="token function">defineTool</span><span class="token punctuation">(</span>
 <span class="token punctuation">{</span>
   name<span class="token punctuation">:</span> <span class="token string">"getOrderStatus"</span><span class="token punctuation">,</span>

   description<span class="token punctuation">:</span> <span class="token string">"Get the status of a user's order by their order ID."</span><span class="token punctuation">,</span>

   inputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
     orderId<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">"The unique ID of the customer's order"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>

   outputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
     status<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
     estimatedDelivery<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token keyword">async</span> <span class="token punctuation">(</span>input<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>input<span class="token punctuation">.</span>orderId <span class="token operator">===</span> <span class="token string">"123-456"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
     <span class="token keyword">return</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">"Shipped"</span><span class="token punctuation">,</span> estimatedDelivery<span class="token punctuation">:</span> <span class="token string">"October 9, 2025"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">return</span> <span class="token punctuation">{</span> status<span class="token punctuation">:</span> <span class="token string">"Not Found"</span><span class="token punctuation">,</span> estimatedDelivery<span class="token punctuation">:</span> <span class="token string">"N/A"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> orderSupportFlow <span class="token operator">=</span> ai<span class="token punctuation">.</span><span class="token function">defineFlow</span><span class="token punctuation">(</span>
 <span class="token punctuation">{</span>
   name<span class="token punctuation">:</span> <span class="token string">"orderSupportFlow"</span><span class="token punctuation">,</span>
   inputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
   outputSchema<span class="token punctuation">:</span> z<span class="token punctuation">.</span><span class="token keyword">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token keyword">async</span> <span class="token punctuation">(</span>prompt<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
   <span class="token keyword">const</span> llmResponse <span class="token operator">=</span> <span class="token keyword">await</span> ai<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
     prompt<span class="token punctuation">:</span> prompt<span class="token punctuation">,</span>
     tools<span class="token punctuation">:</span> <span class="token punctuation">[</span>getOrderStatusTool<span class="token punctuation">]</span><span class="token punctuation">,</span>
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">return</span> llmResponse<span class="token punctuation">.</span>text<span class="token punctuation">;</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>We have a final step to connect Genkit with our favorite AI tool, Gemini.</p><p>Create a file named <code>.env</code> in the <code>genkit-app/backend</code>, next get a free API key from <a target="_blank" href="https://aistudio.google.com/app/apikey">Google AI Studio</a> and add it to the .env file.</p><pre><code>GEMINI_API_KEY="YOUR_API_KEY_HERE"
</code></pre><p>To make our <code>index.ts</code> have access to the .env file, we are going to use the <code>dotenv</code> package. Open the terminal and run <code>npm install dotenv</code>. After it finishes, import <code>dotenv</code> and initialize it.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> dotenv <span class="token keyword">from</span> <span class="token string">"dotenv"</span><span class="token punctuation">;</span>

dotenv<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Because we are using CommonJS, add the field <code>"type: module"</code> to the package.json:</p><pre class=" language-json"><code class="prism  language-json"><span class="token punctuation">{</span>
 <span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"backend"</span><span class="token punctuation">,</span>
 <span class="token string">"version"</span><span class="token punctuation">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span>
 <span class="token string">"type"</span><span class="token punctuation">:</span> <span class="token string">"module"</span><span class="token punctuation">,</span>
 <span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
 <span class="token string">"main"</span><span class="token punctuation">:</span> <span class="token string">"index.js"</span><span class="token punctuation">,</span>
 <span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
   <span class="token string">"test"</span><span class="token punctuation">:</span> <span class="token string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token operator">...</span><span class="token punctuation">.</span>
</code></pre><p>Ok, everything is ready! Let&rsquo;s run our agentic app with the command:</p><pre class=" language-bash"><code class="prism  language-bash"> genkit start -- npx tsx --watch src/index.ts
</code></pre><p>If you want to set a custom port, use the <code>--port</code> flag to set a specific port to run genkit like: <code>genkit start --port 4001 -- npx tsx --watch src/index.ts</code></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image001.png?sfvrsn=1114657c_2" alt="genkit start --port 4001 -- npx tsx --watch src/index.ts" /></p><p>Yes, our agent is running &hellip; but hold on a second. How can we can test the agent if we don&rsquo;t have an app?</p><p>Genkit provides the Developer UI, a local web app that lets us work with models, flows, prompts and other elements in our Genkit projects.</p><p>The Developer UI is running in <code>http://localhost:4001</code> and allows us to use models and call our tools and functions to debug our project.</p><p>In the browser showing the Genkit Developer UI, we&rsquo;re going to focus on testing our code. First, click into Models. It provides a system prompt to ask for the model config and tools.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image003.png?sfvrsn=da7e13bc_2" alt="Config - Model" /></p><p>The config allows us to configure the model, but the key point is in the Tools tab. Click on it and we see our function <code>getOrderStatus</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image005.png?sfvrsn=dfe040c4_2" alt="Tools - getOrderStatus" /></p><p>Before activating our tool, we&rsquo;re going to write a prompt <code>Where is my order 123-456</code>, and click the Run button. The model doesn&rsquo;t have any idea about it.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image007.gif?sfvrsn=99743523_2" alt="Where is my order 123-456? I do not have access to your order information." /></p><p>Finally, click in the tools and select available tools <code>getOrderStatus</code> and run the same question.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2026/2026-01/image008.gif?sfvrsn=6ab93a86_2" alt="Where is my order 123-456 - now with getOrderStatus enabled" /></p><p>Tada!! The model gets the tools and executes our code!! And answers our mock response!</p><p>We built our first agentic app with flows and tools easily with Genkit and brought power to the models!</p><h2 id="recap">Recap</h2><p>We learned about how Genkit helps us to build agentic apps by creating our flows, and how it processes requests and uses tools to make an AI agent smart, combined with Genkit Developer UI to debug, test and play with our flows and tools.</p><p>It helps us to turn on models like Gemini or others to access our data to answer any question.</p><p>It was so nice to use the Genkit Developer UI to test our flow and tools. However, in the real world, we want to connect its power with a real chatbot. So, in the <a href="https://www.telerik.com/blogs/build-agentic-apps-angular-genkit-kendo-ui-part-2" target="_blank">next chapter</a>, we&rsquo;re going to connect Genkit with Angular and build a fast chatbot using the power of Kendo UI!</p><p><a target="_blank" href="https://github.com/danywalls/agentic-app">Source code.</a></p><hr /><p><strong>Go to the next post:</strong> <a href="https://www.telerik.com/blogs/build-agentic-apps-angular-genkit-kendo-ui-part-2" target="_blank">Build Agentic Apps with Angular, Genkit and Kendo UI: Part 2</a></p><img src="https://feeds.telerik.com/link/23055/17252636.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:83f5a17f-b323-4599-b987-180cd238d682</id>
    <title type="text">Data Fetching in Modern Angular</title>
    <summary type="text">See how data fetching has changed in Angular 21 with the resource API and httpResource API.</summary>
    <published>2025-12-29T15:02:18Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17243369/data-fetching-modern-angular"/>
    <content type="text"><![CDATA[<p><span class="featured">See how data fetching has changed in Angular 21 with the resource API and httpResource API.</span></p><p>As I write this article, Angular 21.0 has been released, and it has changed the way data should be fetched in modern Angular apps. Usually, in an Angular application, data comes from an API and can be categorized as:</p><ol><li>Fetching data from the server</li><li>Mutating data on the server</li></ol><p>In modern Angular apps, there are two new <strong>signal-based</strong> ways to fetch data:</p><ol><li>resource API</li><li>httpResource API</li></ol><p>Both the <strong>resource</strong> and <strong>httpResource</strong> APIs serve the same purpose, but they differ in how they make HTTP requests. The <strong>resource</strong> API uses the browser&rsquo;s native <strong>fetch</strong> function, while <strong>httpResource</strong> relies on Angular&rsquo;s <strong>HttpClient</strong> service to perform the request.</p><p>Since <strong>httpResource</strong> uses Angular&rsquo;s built-in <strong>HttpClient</strong>, it automatically works with other Angular features such as <strong>interceptors</strong>.</p><p>To dive deeper, let us start by creating a model interface that represents the API response structure.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span><span class="token keyword">number</span><span class="token punctuation">;</span> 
    name <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
    price <span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
    description<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    cateogry<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Now you can use the <strong>resource</strong> API to fetch data, as shown below. It really is this simple under the hood; it uses the browser&rsquo;s native <strong>fetch</strong> API to perform the HTTP request.</p><pre class=" language-ts"><code class="prism  language-ts">   productApiResource <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/product'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The Resource API returns a WritableResource and has read-only properties such as:</p><ul><li>value</li><li>status</li><li>error</li><li>isLoading</li></ul><p>Besides the above read-only properties, it also has a <strong>hasValue()</strong> function to check whether the resource value property has any value or not.</p><p>You can use the value signal to read the data returned in a reactive context, in this case, a template as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Id<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>description<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    @for(p of productApiResource.value();track p.id) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.id}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.name}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.price}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.description}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    }
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Using the httpResource, you can fetch data from the API as shown in the following code listing.</p><pre class=" language-ts"><code class="prism  language-ts">productApiResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`http://localhost:3000/product`</span></span><span class="token punctuation">,</span>
    method<span class="token punctuation">:</span> <span class="token string">'GET'</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Here, we are passing the URL and the HTTP method (GET) to fetch the data. Like the Resource API, the httpResource API returns a WritableResource and has read-only properties such as:</p><ul><li>value</li><li>status</li><li>error</li><li>isLoading</li></ul><p>In the same way you use the <strong>resource</strong> API, you can also use the <strong>httpResource</strong> API within a reactive context, for example, inside the template, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Id<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>description<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    @for(p of productApiResource.value();track p.id) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.id}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.name}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.price}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.description}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    }
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The primary purposes of both the resource and httpResource APIs are as follows, but they are most often used to fetch data from the server.</p><ul><li>Fetch data from the API</li><li>Update data locally</li><li>Asynchronously load local resource</li></ul><p>Neither of these APIs should be used for server mutations. In other words, avoid using them for HTTP operations like <strong>POST</strong>, <strong>PUT</strong> or <strong>DELETE.</strong> They are intended only for <strong>GET</strong> requests. However, suppose you have API endpoints that return data via a <strong>POST</strong> request without actually mutating data on the server. In that case, you can safely use these APIs for that purpose as well.</p><p>As the resource and httpResource APIs return various signal-based read-only properties, they can be read and tracked within reactive contexts, effects and computed values.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Product Resource Data has value '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Product Resource Data '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Product Resource Staus  '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Product Resource Error '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Product Resource is Loading  '</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">isLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span><span class="token punctuation">)</span>

  <span class="token punctuation">}</span>

  productApiResource <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/product'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Angular prints values as below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/angular-print-values.png?sfvrsn=fe0d2005_2" alt="Product Resource Data has value – false, status – loading, etc." /></p><p>Once the resource is resolved, its properties&rsquo; values are updated, and, because they are signals, the updated values are automatically picked up inside the effect.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/angular-print-values-updated.png?sfvrsn=d0accfdc_2" alt="Product Resource Data has value – true, array 100; status – resolved, etc." /></p><p>As you can see, the status value changes from <code>loading</code> to <code>resolved</code>. Both the <strong>resource</strong> and <strong>httpResource</strong> APIs provide these status values as strings.</p><ol><li><strong>idle</strong> &ndash; The resource has no valid request and will not perform any loading. Here, <code>value()</code> is undefined.</li><li><strong>loading</strong> &ndash; The resource is currently loading a new value. Here, <code>value()</code> is undefined.</li><li><strong>reloading</strong> &ndash; The resource is currently reloading the new value. Here, <code>value()</code> is the previously fetched value.</li><li><strong>error</strong> &ndash; The resource failed to load the value. Here, <code>value()</code> is undefined.</li><li><strong>resolved</strong> &ndash; The resource has completed loading. Here, <code>value()</code> is returned from the loader.</li><li><strong>local</strong> &ndash; The resource value was set locally by <code>set()</code> or <code>update()</code>.</li></ol><p>You can also use these properties to compute other values. For example, if you need to calculate the total price of all products, you can do it as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">  totalPrice <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> products <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> products<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>sum<span class="token punctuation">,</span> product<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> sum <span class="token operator">+</span> product<span class="token punctuation">.</span>price<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>You can use the <code>totalPrice</code> computed signal on the template:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Total Price of Product = {{totalPrice()}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The same explanation applies to <strong>httpResource</strong> as well, since it is built on top of <strong>resource</strong>.</p><p>Sometimes you may need to pass parameters to a resource. For example, if you want to fetch a specific product from the API, you will need to pass its <strong>id</strong>. To support this, the <strong>resource</strong> API accepts an optional params argument that lets you provide these values.</p><pre class=" language-ts"><code class="prism  language-ts">sProduct <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  selectedProductApiResource<span class="token punctuation">:</span> <span class="token keyword">any</span> <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    params<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> id <span class="token operator">=</span> params<span class="token punctuation">.</span>id<span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/product/'</span> <span class="token operator">+</span> id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">selectProduct</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>sProduct<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>Angular tracks the params, so whenever any signal used inside them changes, Angular automatically reruns the resource loader. This is why it&rsquo;s a good practice to pass parameters as signal-based values through params.</p><p>You can use the selected product using the <strong>selectedProductApiResource</strong> as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Selected Product Details<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
@if(selectedProductApiResource.hasValue()){
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Id:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProductApiResource.value()?.id}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Name:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProductApiResource.value()?.name}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Price:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProductApiResource.value()?.price}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Description:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProductApiResource.value()?.description}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>You should avoid reading signal-based inputs directly inside the loader, because the loader itself is not tracked. Even if the signal value changes, Angular will not rerun the loader. As a result, the code below will <strong>not</strong> fetch the product for the selected ID.</p><pre class=" language-ts"><code class="prism  language-ts">  selectedProductApiResource<span class="token punctuation">:</span> <span class="token keyword">any</span> <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/product/'</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The Angular <strong>resource</strong> API does not automatically handle API errors. For example, if you request an ID that doesn&rsquo;t exist and the API returns a <strong>404</strong>, the error property will remain undefined.</p><pre class=" language-ts"><code class="prism  language-ts">selectedProductApiResource<span class="token punctuation">:</span> <span class="token keyword">any</span> <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    params<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// let id = params.id;</span>
      <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token number">340399</span> <span class="token comment">// setting random ID to simulate api error </span>
      <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/product/'</span> <span class="token operator">+</span> id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>
        <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Promise<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Then print different properties in the effect.</p><pre class=" language-ts"><code class="prism  language-ts">  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token function">effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'selected product data -'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'selected product status -'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'selected product error -'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'selected product is loading -'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">isLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>As you see, the error remains undefined and the resource resolves successfully.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/angular-error-undefined.png?sfvrsn=196aa850_2" alt="selected product error – undefined, twice" /></p><p>So, you should handle API errors separately and avoid relying on the error value returned by the resource API. However, any promise rejection will still be reflected in the resource&rsquo;s error status. To see this in action, let&rsquo;s throw a promise error as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">selectedProductApiResource<span class="token punctuation">:</span> <span class="token keyword">any</span> <span class="token operator">=</span> <span class="token function">resource</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    params<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    loader<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> params <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// let id = params.id;</span>
      <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token number">340399</span> <span class="token comment">// setting random ID to simulate api error </span>
      <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Promise rejected for ID: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>params<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>In effect, you will see that the error value is set as shown below:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/error-value-set.png?sfvrsn=36b85e58_2" alt="selected product status – error. selected product error – error – promise rejected for it..." /></p><p>One important thing to remember is that if a resource is in an <strong>error</strong> state and you try to read its <code>value()</code> property, Angular will throw a runtime error. So it&rsquo;s always best practice to read a resource&rsquo;s value only after checking <code>hasValue()</code>, as shown below.</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token function">effect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'selected product data -'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><h2 id="more-about-httpresource-api">More About httpResource API</h2><p>The <strong>httpResource</strong> extends the Resource API by using the HttpClient under the hood.</p><ul><li>The httpResource is built on top of the resource primitive.</li><li>It uses HttpClient as its loader, whereas the Resource API uses fetch.</li><li>It makes HTTP requests via Angular&rsquo;s HTTP stack, so it works with interceptors and related features.</li></ul><p>You can create a httpResource using the httpResource function as shown below:</p><pre class=" language-ts"><code class="prism  language-ts">  productApiResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`http://localhost:3000/product`</span></span><span class="token punctuation">,</span>
    method<span class="token punctuation">:</span> <span class="token string">'GET'</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>The httpResource function creates a <strong>Resource</strong> that fetches data using an HTTP GET request and automatically updates when the URL changes through signals. It uses <strong>HttpClient</strong>, so it supports interceptors, testing tools and all HttpClient features. The response is parsed as JSON by default, with options like <code>httpResource.text()</code> for alternate parsing.</p><p>Let&rsquo;s look at how you can use <strong>httpResource</strong> effectively to fetch data and bind it to a component.</p><p>The first thing is to create the httpResource inside an Angular service as shown below:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ProductService</span> <span class="token punctuation">{</span>

  productApiResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`http://localhost:3000/product`</span></span><span class="token punctuation">,</span>
    method<span class="token punctuation">:</span> <span class="token string">'GET'</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>Next, in the component, read the value signal from the <strong>httpResource</strong> inside a computed signal, as shown below.</p><pre class=" language-ts"><code class="prism  language-ts">@<span class="token function">Component</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
<span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Product</span> <span class="token punctuation">{</span>

  productService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>ProductService<span class="token punctuation">)</span><span class="token punctuation">;</span>
  products <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>productApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>On the template, render the fetched response as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Id<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>description<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    @for(p of products();track p.id) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.id}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.name}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.price}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{p.description}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span> select(p.id)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>select<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    }
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>We have added a <strong>Select</strong> button to choose a specific product. To support this in the service:</p><ul><li>Add a signal to store the selected product&rsquo;s ID.</li><li>Add a resource that fetches the selected product based on that ID.</li></ul><pre class=" language-ts"><code class="prism  language-ts">  <span class="token keyword">public</span> selectedProduct<span class="token punctuation">:</span> WritableSignal<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span> <span class="token operator">=</span> signal<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   selectedProductApiResource  <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`http://localhost:3000/product/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">selectedProduct</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">,</span>
    method<span class="token punctuation">:</span> <span class="token string">'GET'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><p>Then, in the component, set the selected ID and read the selected product through a computed signal.</p><pre class=" language-ts"><code class="prism  language-ts">  selectedProduct <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>selectedProductApiResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">select</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>selectedProduct<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>You may also notice that, unlike a resource, httpResource automatically tracks any signals used in the URL. Since the ID is part of the URL, each time the ID changes, httpResource triggers a new API call. On the template, the selected product can be displayed as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Selected Product Details<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Id:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProduct()?.id}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Name:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProduct()?.name}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Price:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProduct()?.price}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>b</span><span class="token punctuation">&gt;</span></span>Description:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>b</span><span class="token punctuation">&gt;</span></span> {{selectedProduct()?.description}} <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span><span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>This is how you can use <strong>httpResource</strong> to fetch data from an API and consume it in a component.</p><p>By default, httpResource parses the response as JSON. To handle other data types, it provides dedicated methods for other response types. They are as follows:</p><ul><li><strong>httpResource.text</strong> fetches data as plain text</li><li><strong>httpResource.blob</strong> fetches as a blob</li><li><strong>httpResource.arrayBuffer</strong> fetches data as an ArrayBuffer</li></ul><p>For example, you can download an image blob using the httpResource as shown below:</p><pre><code>imageName: WritableSignal&lt;string&gt; = signal&lt;string&gt;('a.png');
  imageResource = httpResource.blob&lt;any&gt;(() =&gt; ({
    url: `http://localhost:3000/product/image/${this.imageName()}`,
    method: 'GET',
    type: 'blob'
  }));
</code></pre><p>Then, in the component, read the image blob in the computed signal.</p><pre class=" language-ts"><code class="prism  language-ts">  productImage <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>imageResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> blob <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productService<span class="token punctuation">.</span>imageResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Blob Image '</span><span class="token punctuation">,</span> blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> URL<span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Then, in the template, use the computed signal as the source of an image:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">[src]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productImage()<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
</code></pre><p>For advanced requests, the httpResource API supports a request object with several fields. Among them, only the URL is required&mdash;all other fields are optional.</p><ul><li>url</li><li>method</li><li>body</li><li>params</li><li>headers</li><li>context</li><li>reportProgress</li><li>withCredentials</li><li>transferCache</li><li>timeOut</li><li>Etc.</li></ul><p>Although the httpResource object supports other verbs, such as POST, PUT and DELETE, it is advisable to use the httpResource API only to fetch data from the backend and not to perform mutations using other HTTP verbs.</p><h2 id="summary">Summary</h2><p>In modern Angular, where reactivity is powered by signals, <strong>resource</strong> and <strong>httpResource</strong> should be used to fetch data from APIs. These two APIs, combined with deferred views, form the foundation of building robust, modern Angular applications.</p><p>I hope you found this article helpful. Thanks for reading.</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular 21: My Favorite New Features, a Quick Demo and a Look at What&rsquo;s Next</h4></div><div class="col-8"><p class="u-fs16 u-mb0">See what else you may have missed that is <a target="_blank" href="https://www.telerik.com/blogs/angular-21-my-favorite-new-features-quick-demo-look-whats-next">new in Angular 21</a>.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17243369.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:60c128f1-d4ad-48d7-a80b-4c1924c8a699</id>
    <title type="text">A Practical Guide for State Management Using Angular Services and Signals</title>
    <summary type="text">Learn how Angular Services with Signals can simplify your application architecture and handle state management. Let’s do it!</summary>
    <published>2025-12-16T17:46:26Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dhananjay Kumar </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17235702/practical-guide-state-management-using-angular-services-signals"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how Angular Services with Signals can simplify your application architecture and handle state management. Let&rsquo;s do it!</span></p><p>Let me start by saying that NgRx is excellent and the right choice in certain situations. But it also brings a lot of setup work and a steep learning curve.</p><p>For many years, Angular developers tried to avoid NgRx by using RxJS Subjects and complex observable pipelines, but that also gets difficult. You need to understand many operators, how they work and even learn marble diagrams.</p><p>For most applications, especially small- to medium-sized ones, you don&rsquo;t need all this complexity.</p><p>With the introduction of Signals and modern data-fetching APIs like <strong>resource</strong> and <strong>httpResource</strong>, Angular now offers a simpler, more intuitive state management approach built directly into the framework.</p><p>In this article, we will explore how <strong>Angular Services + Signals</strong> can significantly simplify your application architecture and handle state management.</p><p>Let&rsquo;s build a Signal-based store step by step. To start with, create an interface to model the API response.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IProduct</span> <span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    name<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    description<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span>
    price<span class="token punctuation">:</span> <span class="token keyword">string</span> <span class="token punctuation">;</span>
    category<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">;</span> 
<span class="token punctuation">}</span>
</code></pre><p>Then, add a service called <code>ProductStore</code>. You can consider it as a signal store that:</p><ul><li>Holds application state using <code>signal()</code></li><li>Computes derived values using <code>computed()</code> or <code>linkedSignal()</code></li><li>Reacts to changes using <code>effect()</code></li><li>Exposes methods that update the state</li></ul><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Injectable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Productstrore</span> <span class="token punctuation">{</span>
  
<span class="token punctuation">}</span>
</code></pre><p>We are going to follow this approach:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/state-signal-fetching-httpresource.png?sfvrsn=15fc2662_2" alt="State – Signal. Data fetching – httpResource. Derived state – computed / linkSignal. Changes – effects." /></p><p>Let&rsquo;s start with fetching data from the API using the httpResource API.</p><pre class=" language-typescript"><code class="prism  language-typescript">productsResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  url<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>apiUrl<span class="token punctuation">,</span>
  method<span class="token punctuation">:</span> <span class="token string">'GET'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Next, let&rsquo;s create a reactive state to hold the resource&rsquo;s <strong>value</strong>, <strong>status</strong> and <strong>error</strong>. We&rsquo;ll use <code>computed()</code> for this because httpResource exposes these fields as <strong>read-only signals</strong>.</p><pre class=" language-typescript"><code class="prism  language-typescript">products <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
  loading <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">isLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  error <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  status <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Also, add a method to refresh the resource so that whenever data is added or mutated, it reloads.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">reload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>As of now, we have data in place in a reactive way. Now, let&rsquo;s use this on a component to display the products.</p><pre class=" language-typescript"><code class="prism  language-typescript">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-product'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./product.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./product.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Product</span> <span class="token punctuation">{</span>

    store  <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Productstrore<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>And in the template, we can use all the computed signals from the state, as shown below.</p><pre class=" language-typescript"><code class="prism  language-typescript">@<span class="token keyword">if</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span><span class="token function">products</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token operator">&lt;</span>table <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"table"</span><span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span>tr<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>th<span class="token operator">&gt;</span>Id<span class="token operator">&lt;</span><span class="token operator">/</span>th<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>th<span class="token operator">&gt;</span>Name<span class="token operator">&lt;</span><span class="token operator">/</span>th<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>th<span class="token operator">&gt;</span>Price<span class="token operator">&lt;</span><span class="token operator">/</span>th<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>th<span class="token operator">&gt;</span>Cateogry<span class="token operator">&lt;</span><span class="token operator">/</span>th<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>tr<span class="token operator">&gt;</span>
    @<span class="token keyword">for</span><span class="token punctuation">(</span>product <span class="token keyword">of</span> store<span class="token punctuation">.</span><span class="token function">products</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>track product<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>tr<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>td<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span>product<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>td<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span>product<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>td<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span>product<span class="token punctuation">.</span>price<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>td<span class="token operator">&gt;</span><span class="token punctuation">{</span><span class="token punctuation">{</span>product<span class="token punctuation">.</span>category<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span>td<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>tr<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token operator">/</span>table<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
@<span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span><span class="token function">loading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"text-center"</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"spinner-border text-primary"</span> role<span class="token operator">=</span><span class="token string">"status"</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"visually-hidden"</span><span class="token operator">&gt;</span>Loading<span class="token operator">...</span><span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
@<span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>store<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"alert alert-danger text-center"</span><span class="token operator">&gt;</span>
        <span class="token punctuation">{</span><span class="token punctuation">{</span>store<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token punctuation">}</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>
</code></pre><p>As of now, you have fetched data from the store and displayed it in the component.</p><h2 id="adding-record">Adding Record</h2><p>Now, let&rsquo;s add functionality to the store to create a new record using the API. To do this, we will add two signals and their corresponding computed signals to track the loading and error states.</p><pre class=" language-typescript"><code class="prism  language-typescript">  <span class="token keyword">private</span> addProductLoading <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">private</span> addProductError <span class="token operator">=</span> signal<span class="token operator">&lt;</span><span class="token keyword">string</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  isAddingProduct <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addProductLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  isAddProductError <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addProductError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Next, add a function that sends a POST request to the endpoint to create a new product. Since we&rsquo;re adding a new record, we would not use httpResource. Instead, we will use HttpClient to perform the POST operation. In this function, we&rsquo;ll also update the loading and error signals based on the response.</p><pre class=" language-typescript"><code class="prism  language-typescript">   <span class="token function-variable function">addProduct</span> <span class="token operator">=</span> <span class="token punctuation">(</span>product<span class="token punctuation">:</span> IProduct<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    
    <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span>post<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>apiUrl<span class="token punctuation">,</span> product<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      next<span class="token punctuation">:</span> <span class="token punctuation">(</span>newProduct<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      error<span class="token punctuation">:</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error adding product:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductError<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'Failed to add product'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token punctuation">}</span>

</code></pre><p>As of now, we have added a product using the old httpClient, but handling the response in a reactive way using the signals. Now, let&rsquo;s use this on a component to add a product. On the component, to add a product, let&rsquo;s create a signal form.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AddProduct</span> <span class="token punctuation">{</span>

  store <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Productstrore<span class="token punctuation">)</span><span class="token punctuation">;</span>
  
  productModel <span class="token operator">=</span> signal<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    id<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
    name<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
    description<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
    price<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
    category<span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  productForm <span class="token operator">=</span> <span class="token function">form</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productModel<span class="token punctuation">)</span>

  <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">productModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Adding product:'</span><span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>store<span class="token punctuation">.</span><span class="token function">addProduct</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><p>Next, in the template, create a form and use the store&rsquo;s loading and error signals to handle the UI, as shown below.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-center text-info<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Add Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form form-group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">[field]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.id<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Enter Id<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">[field]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.name<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Enter Name<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">[field]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.price<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Enter Price<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">[field]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.description<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Enter Description<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">[field]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>productForm.category<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Enter Cateogry<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>add()<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Add<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>

@if(store.isAddingProduct()){
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-center mt-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>spinner-border text-primary<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>status<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>visually-hidden<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Adding...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
@else if(store.isAddProductError()){
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>alert alert-danger text-center mt-3<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    {{store.isAddProductError()}}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>If you place the <strong>AddProduct</strong> component and the <strong>Product</strong> component next to each other, as shown below, then as soon as you add a new product, the Product component will automatically update with the latest list.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-md-7<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-product</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>app-product</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-md-5<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-add-product</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>app-add-product</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>The expected output should be as follows: list products and add a product from the store.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/product-list-add.png?sfvrsn=cd50dc4f_2" alt="Product list with id, name, price, category. Add product form with corresponding fields." /></p><p>Putting everything together, the <strong>ProductStore</strong> now looks like this. It fetches data from the API and adds new records using the API. The entire store is fully reactive and uses signals and related concepts for all operations.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> HttpClient<span class="token punctuation">,</span> httpResource <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/common/http'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> computed<span class="token punctuation">,</span> inject<span class="token punctuation">,</span> Injectable<span class="token punctuation">,</span> signal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> IProduct <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./product-model'</span><span class="token punctuation">;</span>

@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Productstrore</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> readonly apiUrl <span class="token operator">=</span> <span class="token string">'http://localhost:3000/product'</span><span class="token punctuation">;</span>
  <span class="token keyword">private</span> http <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>HttpClient<span class="token punctuation">)</span><span class="token punctuation">;</span>

  productsResource <span class="token operator">=</span> httpResource<span class="token operator">&lt;</span>IProduct<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
    url<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>apiUrl<span class="token punctuation">,</span>
    method<span class="token punctuation">:</span> <span class="token string">'GET'</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  products <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">hasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  loading <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">isLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  error <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  status <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>productsResource<span class="token punctuation">.</span><span class="token function">reload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">private</span> addProductLoading <span class="token operator">=</span> <span class="token function">signal</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">private</span> addProductError <span class="token operator">=</span> signal<span class="token operator">&lt;</span><span class="token keyword">string</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  isAddingProduct <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addProductLoading</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  isAddProductError <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">addProductError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function-variable function">addProduct</span> <span class="token operator">=</span> <span class="token punctuation">(</span>product<span class="token punctuation">:</span> IProduct<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span>post<span class="token operator">&lt;</span>IProduct<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>apiUrl<span class="token punctuation">,</span> product<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      next<span class="token punctuation">:</span> <span class="token punctuation">(</span>newProduct<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      error<span class="token punctuation">:</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error adding product:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductLoading<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>addProductError<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string">'Failed to add product'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h2 id="creating-cart-store">Creating Cart Store</h2><p>Building a cart is one of the most common examples of state management. So let&rsquo;s walk through how to create it. In the cart store, the user should be able to:</p><ul><li>Add a product to the cart</li><li>Increase quantity</li><li>Decrease quantity</li><li>Clear the cart</li></ul><p>To start with, create an interface to model the Cart.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> IProduct <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./product-model"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">ICartItem</span> <span class="token punctuation">{</span>
  product<span class="token punctuation">:</span> IProduct<span class="token punctuation">;</span>
  quantity<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
  subtotal<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><p>Then, add a service called <strong>Cartstore</strong>.</p><pre class=" language-typescript"><code class="prism  language-typescript">@<span class="token function">Injectable</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  providedIn<span class="token punctuation">:</span> <span class="token string">'root'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Cartstore</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> _cartItems <span class="token operator">=</span> signal<span class="token operator">&lt;</span>ICartItem<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  cartItems <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  cartCount <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>total<span class="token punctuation">,</span> item<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> total <span class="token operator">+</span> item<span class="token punctuation">.</span>quantity<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  cartTotal <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>total<span class="token punctuation">,</span> item<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> total <span class="token operator">+</span> item<span class="token punctuation">.</span>subtotal<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  isEmpty <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><p>In the Cartstore, we have added:</p><ul><li>Computed Signal to hold cart items</li><li>Computed signal to count the total quantity</li><li>Computed signal to calculate the total price</li><li>Computed signal to empty the cart</li></ul><p>Next, add a function that either adds a product to the cart or updates its quantity if the product is already in the cart.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token function">addToCart</span><span class="token punctuation">(</span>product<span class="token punctuation">:</span> IProduct<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> currentItems <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> existingItemIndex <span class="token operator">=</span> currentItems<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> item<span class="token punctuation">.</span>product<span class="token punctuation">.</span>id <span class="token operator">===</span> product<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>existingItemIndex <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> updatedItems <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>currentItems<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> existingItem <span class="token operator">=</span> updatedItems<span class="token punctuation">[</span>existingItemIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> newQuantity <span class="token operator">=</span> existingItem<span class="token punctuation">.</span>quantity <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> price <span class="token operator">=</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>price<span class="token punctuation">)</span><span class="token punctuation">;</span>

      updatedItems<span class="token punctuation">[</span>existingItemIndex<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token operator">...</span>existingItem<span class="token punctuation">,</span>
        quantity<span class="token punctuation">:</span> newQuantity<span class="token punctuation">,</span>
        subtotal<span class="token punctuation">:</span> price <span class="token operator">*</span> newQuantity
      <span class="token punctuation">}</span><span class="token punctuation">;</span>

      <span class="token keyword">this</span><span class="token punctuation">.</span>_cartItems<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span>updatedItems<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> price <span class="token operator">=</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>price<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> quantity <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> newItem<span class="token punctuation">:</span> ICartItem <span class="token operator">=</span> <span class="token punctuation">{</span>
        product<span class="token punctuation">,</span>
        quantity<span class="token punctuation">,</span>
        subtotal<span class="token punctuation">:</span> price <span class="token operator">*</span> quantity
      <span class="token punctuation">}</span><span class="token punctuation">;</span>

      <span class="token keyword">this</span><span class="token punctuation">.</span>_cartItems<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>items <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token operator">...</span>items<span class="token punctuation">,</span> newItem<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
</code></pre><p>If you look at the function above, most of the logic is simple array manipulation. After updating the array, we set the <code>cartItems</code> signal to share the updated state.</p><p>In the same way, you can create a function to remove a product from the cart.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token function">removeFromCart</span><span class="token punctuation">(</span>productId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> currentItems <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_cartItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> item <span class="token operator">=</span> currentItems<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> item<span class="token punctuation">.</span>product<span class="token punctuation">.</span>id <span class="token operator">===</span> productId<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token operator">?</span><span class="token punctuation">.</span>quantity <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>_cartItems<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>items <span class="token operator">=&gt;</span>
          items<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> item<span class="token punctuation">.</span>product<span class="token punctuation">.</span>id <span class="token operator">!==</span> productId<span class="token punctuation">)</span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> price <span class="token operator">=</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>item<span class="token operator">!</span><span class="token punctuation">.</span>product<span class="token punctuation">.</span>price<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> quantity <span class="token operator">=</span> item<span class="token operator">!</span><span class="token punctuation">.</span>quantity <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>_cartItems<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>items <span class="token operator">=&gt;</span>
          items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>product<span class="token punctuation">.</span>id <span class="token operator">===</span> productId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token keyword">return</span> <span class="token punctuation">{</span>
                <span class="token operator">...</span>item<span class="token punctuation">,</span>
                quantity<span class="token punctuation">,</span>
                subtotal<span class="token punctuation">:</span> price <span class="token operator">*</span> quantity
              <span class="token punctuation">}</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> item<span class="token punctuation">;</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
</code></pre><p>Again, most of the logic is simple array manipulation. After updating the array, we set the <code>cartItems</code> signal to share the updated state.</p><p>As of now, we have <code>Cartstore</code> in place. Now, let&rsquo;s use this on a component to display the carts. For that, first inject the store into the component.</p><pre class=" language-typescript"><code class="prism  language-typescript">@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token punctuation">:</span> <span class="token string">'app-cart'</span><span class="token punctuation">,</span>
  imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>CurrencyPipe<span class="token punctuation">]</span><span class="token punctuation">,</span>
  templateUrl<span class="token punctuation">:</span> <span class="token string">'./cart.html'</span><span class="token punctuation">,</span>
  styleUrl<span class="token punctuation">:</span> <span class="token string">'./cart.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Cart</span> <span class="token punctuation">{</span>

  store <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Cartstore<span class="token punctuation">)</span><span class="token punctuation">;</span>
  
<span class="token punctuation">}</span>
</code></pre><p>On the template, display the carts and total price using the computed signals from the store as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Cart<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>list-group<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        @for(item of store.cartItems();track item.product.id){
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>list-group-item<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        {{ item.product.name }} - {{ item.quantity }} x {{ item.product.price | currency}} =  {{ item.subtotal |currency}}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    }
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span><span class="token punctuation">&gt;</span></span>Total Price = {{store.cartTotal()|currency}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>Also, in the <strong>Product</strong> component, inject the <code>Cartstore</code> and add functions to add and remove from the cart as shown below:</p><pre class=" language-typescript"><code class="prism  language-typescript"> cartstore <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Cartstore<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">addToCart</span><span class="token punctuation">(</span>product<span class="token punctuation">:</span> IProduct<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>cartstore<span class="token punctuation">.</span><span class="token function">addToCart</span><span class="token punctuation">(</span>product<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token function">removeFromCart</span><span class="token punctuation">(</span>productId<span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>cartstore<span class="token punctuation">.</span><span class="token function">removeFromCart</span><span class="token punctuation">(</span>productId<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
</code></pre><p>On the template, update the Product table with two buttons for add and remove as shown below:</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>table</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>table<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Id<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Name<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Price<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>th</span><span class="token punctuation">&gt;</span></span>Cateogry<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>th</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>tr</span><span class="token punctuation">&gt;</span></span>
    @for(product of store.products();track product.id) {
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>tr</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{product.id}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{product.name}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{product.price}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>{{product.category}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>td</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-primary<span class="token punctuation">"</span></span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>addToCart(product)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>btn btn-danger<span class="token punctuation">"</span></span> <span class="token attr-name">(click)</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>removeFromCart(product.id)<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>td</span><span class="token punctuation">&gt;</span></span>
}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>table</span><span class="token punctuation">&gt;</span></span>
</code></pre><p>By putting everything together, the output should be:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/product-list-total-price.png?sfvrsn=dbf00d5e_2" alt="Products list now includes + and - options. The Cart shows total price." /></p><p>We are using the Product, AddProduct and Cart components together within the App component.</p><pre class=" language-html"><code class="prism  language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>row<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-md-7<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-product</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>app-product</span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-md-5<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-add-product</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>app-add-product</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>app-cart</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>app-cart</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre><h2 id="summary">Summary</h2><p>In this article, you learned that it is completely possible to create and manage state in an Angular application using <strong>signals</strong>, <strong>computed</strong> and <strong>httpResource</strong>. With these modern Angular features, you can avoid the complexity of NgRx and still build clean, reactive state management for your app.</p><p>I hope you found this helpful. Thanks for reading!</p><aside><hr data-sf-ec-immutable="" /><div class="row"><div class="col-4 u-normal-full u-small-mb0"><h4 class="u-fs20 u-fw5 u-lh125 u-mb0">Angular Signals: Building a Reactive Countdown Timer</h4></div><div class="col-8"><p class="u-fs16 u-mb0">A comprehensive tutorial for experienced Angular developers to learn <a target="_blank" href="https://www.telerik.com/blogs/angular-signals-building-reactive-countdown-timer">Angular Signals by building a practical countdown timer</a> application with computed signals and effects.</p></div></div></aside><img src="https://feeds.telerik.com/link/23055/17235702.gif" height="1" width="1"/>]]></content>
  </entry>
  <entry>
    <id>urn:uuid:9962132e-1fe5-48b1-82f7-bab35ca2a4cf</id>
    <title type="text">Building Apps with Angular and GraphQL: From REST to GraphQL Part 2</title>
    <summary type="text">Learn how to connect Angular apps to GraphQL using Apollo, from setup and mocking to real REST API integration.</summary>
    <published>2025-12-09T16:12:50Z</published>
    <updated>2026-04-08T22:07:51Z</updated>
    <author>
      <name>Dany Paredes </name>
    </author>
    <link rel="alternate" href="https://feeds.telerik.com/link/23055/17227877/building-apps-angular-graphql-rest-graphql-part-2"/>
    <content type="text"><![CDATA[<p><span class="featured">Learn how to connect Angular apps to GraphQL using Apollo, from setup and mocking to real REST API integration.</span></p><p>In the previous <a target="_blank" href="https://www.telerik.com/blogs/building-apps-angular-graphql-part-1">article about GraphQL</a>, we learned how to set up a GraphQL server, use mock data examples and the basics of creating queries to the server. When building apps using GraphQL, it changes the common pattern to get data in our apps, moving away from creating services with specific methods to retrieve data for each view case or returning unnecessary data.</p><p>We have two options: Create new methods for each version of the data with more or fewer detailed properties, or bring all data and use the <a target="_blank" href="https://rxjs.dev/api/operators/map">Map</a> RxJS operator to transform the data, mapping and returning only the required fields. However, this happens after requesting all data, which means the workload of bringing the data doesn&rsquo;t change; we only transform it.</p><p>GraphQL simplifies the process using queries, and today we are going to learn how to integrate Apollo GraphQL in Angular using a modern data fetching strategy and provide more flexibility in how your frontend components request data using the power of GraphQL and <a target="_blank" href="https://github.com/apollographql/apollo-client">GraphQL Apollo</a>.</p><p>Let&rsquo;s dive in!</p><h2 id="setting-up-the-project">Setting Up the Project</h2><p>Before we start, remember this article is a continuation, so you can <a target="_blank" href="https://www.telerik.com/blogs/building-apps-angular-graphql-part-1">read Part 1</a> or continue by cloning the repository and pointing to the <code class="inline-code">graphql-server-start</code> branch.</p><pre class=" language-bash"><code class="prism  language-bash"><span class="token function">git</span> clone -b graphql-server-start --single-branch https://github.com/danywalls/graphql-and-angular.git
</code></pre><p>Next we need to install dependencies for our Angular app by running <code class="inline-code">npm install</code>. Our next step is installing the necessary packages to connect our Angular with GraphQL using the following packages:</p><ul><li>The <code class="inline-code">graphql</code> package &ndash; iThe os core GraphQL implementation</li><li><code class="inline-code">@apollo/client</code> &ndash; The Apollo client package with caching capabilities</li><li><code class="inline-code">@apollo-angular</code> &ndash; Angular-specific bindings for Apollo client</li></ul><p>In the terminal, run <code class="inline-code">npm install @apollo/client apollo-angular graphql</code>.</p><pre class=" language-bash"><code class="prism  language-bash">dany@mac graphql-and-angular % <span class="token function">npm</span> <span class="token function">install</span> @apollo/client apollo-angular graphql
up to date, audited 1224 packages <span class="token keyword">in</span> 3s
Run <span class="token variable"><span class="token variable">`</span><span class="token function">npm</span> audit<span class="token variable">`</span></span> <span class="token keyword">for</span> details.
dany@mac graphql-and-angular % 
</code></pre><p>After that&rsquo;s complete, run <code class="inline-code">ng serve</code> to see the project running. In your browser, open <code class="inline-code">http://localhost:4200</code> and our project is up and running!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/ng-serve-project-running.png?sfvrsn=608e27a6_2" alt="ng serve on http://localhost:4200 - project is up and running!" /></p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/localhost-kendo-store-running.png?sfvrsn=22186b0d_2" alt="Kendo Store on localhost:4200 in browser" /></p><p>Perfect. Let&rsquo;s move to running the GraphQL server. Open a new terminal in the same workspace project. Move to the <code class="inline-code">server</code> directory and run <code class="inline-code">npm i</code> to install the dependencies and <code class="inline-code">npm run start</code> to initialize the GraphQL server.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/npm-run-start-graphql.png?sfvrsn=ee1a6fe5_2" alt="npm run start to initialize graphql server" /></p><p>In your browser, open the GraphQL server in <code class="inline-code">http://localhost:4000</code>.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/graphql-server-local-browser.png?sfvrsn=9a0c30e3_2" alt="GraphQL server in browser localhost 4000" /></p><p>Perfect! We have all pieces working together, so now it&rsquo;s time to configure Apollo in our Angular!</p><h2 id="apollo-and-angular">Apollo and Angular</h2><p>Before we start typing code, I want to explain what Apollo Angular or Apollo Client is. Apollo Client or Apollo Angular is a client for GraphQL to make data-fetching easy in Angular components or services. It works with agnostic GraphQL or Schema, with an incremental learning curve starting from basic queries and moving to complex scenarios, making our app react to changes using the reactive RxJS system.</p><blockquote><p>Apollo works also with <a target="_blank" href="https://www.telerik.com/blogs/how-to-bind-the-kendo-ui-grid-to-a-graphql-api">Vue</a> and <a target="_blank" href="https://www.telerik.com/blogs/react-basics-getting-started-react-graphql">React</a>!</p></blockquote><p>It&rsquo;s time to move to coding, so let&rsquo;s configure Angular with Apollo!</p><p>Open the <code class="inline-code">app.config.ts</code> file to set up the Apollo Client and import <code class="inline-code">provideApollo</code>, <code class="inline-code">HttpLink</code> to connect our client with our GraphQL Server and <code class="inline-code">InMemoryCache</code> help to store the data <a target="_blank" href="https://the-guild.dev/graphql/apollo-angular/docs/caching/configuration">in cache by default</a> in Apollo 3.0:</p><pre class=" language-ts"><code class="prism  language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span>provideApollo<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'apollo-angular'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>HttpLink<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'apollo-angular/http'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>InMemoryCache<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@apollo/client/core'</span><span class="token punctuation">;</span>
</code></pre><p>Use the <code class="inline-code">provideApollo()</code> function in our application provider. It helps to set up a connection to the GraphQL server at <code class="inline-code">http://localhost:4000/graphql</code> using in-memory cache for Apollo to store query results and makes Apollo available via dependency injection.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token function">provideApollo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> httpLink <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>HttpLink<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        link<span class="token punctuation">:</span> httpLink<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>uri<span class="token punctuation">:</span> <span class="token string">'http://localhost:4000/graphql'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        cache<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">InMemoryCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</code></pre><p>The final code in app.config.ts looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>provideApollo<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'apollo-angular'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>HttpLink<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'apollo-angular/http'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>InMemoryCache<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@apollo/client/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>ApplicationConfig<span class="token punctuation">,</span> inject<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/core"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>provideHttpClient<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common/http"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>provideRouter<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/router"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>routes<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./app.routes"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> appConfig<span class="token punctuation">:</span> ApplicationConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
 providers<span class="token punctuation">:</span> <span class="token punctuation">[</span>
   <span class="token function">provideRouter</span><span class="token punctuation">(</span>routes<span class="token punctuation">)</span><span class="token punctuation">,</span>
   <span class="token function">provideHttpClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// Required by apollo-angular</span>
   <span class="token function">provideApollo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
     <span class="token keyword">const</span> httpLink <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>HttpLink<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">return</span> <span class="token punctuation">{</span>
       link<span class="token punctuation">:</span> httpLink<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>uri<span class="token punctuation">:</span> <span class="token string">'http://localhost:4000/graphql'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
       cache<span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token class-name">InMemoryCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
     <span class="token punctuation">}</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>The configuration is done! We are ready to start querying data using Apollo Service!</p><h2 id="apollo-service-and-graphql-query">Apollo Service and GraphQL Query</h2><p>Before writing our first query, let&rsquo;s see what&rsquo;s happening in our app. In the browser, navigate to the app <code class="inline-code">http://localhost:4200</code> and open the developer tools. In the console, we print the response of the server.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/console-print.png?sfvrsn=a66c1e69_2" alt="Browser with Console open" /></p><p>Take a look into the response. It does include some fields that are useless for our component, like category, rating and description.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/console-response.png?sfvrsn=74ba5e04_2" alt="Closer look at response - category, description, id, image, price, rating, title" /></p><p>I wish to define the exact data our components need using a GraphQL query, so let&rsquo;s open the <code class="inline-code">products.component.ts</code> and remove <code class="inline-code">productService</code> and <code class="inline-code">products$</code>:</p><pre class=" language-ts"><code class="prism  language-ts">productsService <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>ProductsService<span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">public</span> products$ <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productsService<span class="token punctuation">.</span>products$<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
   <span class="token function">tap</span><span class="token punctuation">(</span>p <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span>
 <span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>So the part we are removing looks like this crossed-out section:</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/code-update.png?sfvrsn=60905a4a_2" alt="" sf-size="207745" /></p><p>And ends up like this:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>Component<span class="token punctuation">,</span> inject<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>ProductsService<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../services/products.service"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>AsyncPipe<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>RouterLink<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/router"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>tap<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rxjs"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
 selector<span class="token punctuation">:</span> <span class="token string">'app-products'</span><span class="token punctuation">,</span>
 imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>AsyncPipe<span class="token punctuation">,</span> RouterLink<span class="token punctuation">]</span><span class="token punctuation">,</span>
 templateUrl<span class="token punctuation">:</span> <span class="token string">'./products.component.html'</span><span class="token punctuation">,</span>
 styleUrl<span class="token punctuation">:</span> <span class="token string">'./products.component.scss'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ProductsComponent</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
</code></pre><p>Our next step is to create a query importing <code class="inline-code">Apollo</code> and <code class="inline-code">gql</code>, and, for debugging query responses, import <code class="inline-code">map</code> and <code class="inline-code">tap</code> operators from RxJS.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>Apollo<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"apollo-angular"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> gql <span class="token keyword">from</span> <span class="token string">"graphql-tag"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>map<span class="token punctuation">,</span> tap<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rxjs"</span><span class="token punctuation">;</span>
</code></pre><p>Using the <code class="inline-code">gql</code> tag, declare a <code class="inline-code">PRODUCTS_QUERY</code>. It only needs the <code class="inline-code">id</code>, <code class="inline-code">price</code>, <code class="inline-code">image</code> and <code class="inline-code">title</code> fields. No additional fields will be returned, keeping your payload small.</p><pre class=" language-typescript"><code class="prism  language-typescript">PRODUCTS_QUERY <span class="token operator">=</span> gql<span class="token template-string"><span class="token string">`
  {
    products {
      id
      price
      image
      title
    }
  }
`</span></span><span class="token punctuation">;</span>
</code></pre><p>Now, modify your component to fetch data using Apollo instead of a traditional service. We inject <code class="inline-code">Apollo</code> service in <code class="inline-code">product.component.ts</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">private</span> readonly apollo <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Apollo<span class="token punctuation">)</span>
</code></pre><p>Next, define a new observable <code class="inline-code">products$</code> using <code class="inline-code">apollo</code> service using the <code class="inline-code">watchQuery</code> that fetches and processes the data. Set the query parameter with <code class="inline-code">PRODUCTS_QUERY</code>.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">public</span> products$ <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>apollo<span class="token punctuation">.</span>watchQuery<span class="token operator">&lt;</span><span class="token punctuation">{</span> products<span class="token punctuation">:</span> Product<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  query<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>PRODUCTS_QUERY
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>valueChanges<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
  <span class="token function">tap</span><span class="token punctuation">(</span>response <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'GraphQL response:'</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token function">map</span><span class="token punctuation">(</span>result <span class="token operator">=&gt;</span> result<span class="token punctuation">.</span>data<span class="token punctuation">.</span>products<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote><p>The Angular App reacts to changes using <code class="inline-code">async</code> pipe in the products.component.html.</p></blockquote><pre class=" language-html"><code class="prism  language-html">@if (products$ | async; as products) {
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
   @for(product of products; track product) {
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">[routerLink]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>[<span class="token punctuation">'</span>product-detail<span class="token punctuation">'</span>, product.id]<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>bg-white border border-gray-200 rounded-xl shadow hover:shadow-xl transition-shadow p-6 flex flex-col items-center<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">[src]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>product.image<span class="token punctuation">"</span></span> <span class="token attr-name">[width]</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>180<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{product.title}}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mb-5 rounded-lg object-cover h-44 w-44 border border-gray-100 shadow-sm<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-lg font-semibold mb-2 text-gray-800 text-center line-clamp-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{product.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">&gt;</span></span>
       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text-green-600 font-bold text-2xl mb-2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>${{product.price}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
   }
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
}
</code></pre><p>What are Apollo, <code class="inline-code">watchQuery</code> and <code class="inline-code">PRODUCTS_QUERY</code> doing?</p><p>First, we use the query to specify exactly which fields you need, preventing over-fetching. In our query, we only request <code class="inline-code">id</code>, <code class="inline-code">price</code>, <code class="inline-code">image</code> and <code class="inline-code">title</code>. If your UI only shows these fields, you don&rsquo;t need to fetch additional data.</p><p>The query is strongly typed with <code class="inline-code">product</code> type, because Apollo&rsquo;s <code class="inline-code">watchQuery</code> returns an observable that automatically updates when the cache is modified, keeping your UI in sync with your data.</p><p>The final code in <code class="inline-code">products.component.ts</code> looks like this:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>Component<span class="token punctuation">,</span> inject<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>AsyncPipe<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/common"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>RouterLink<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@angular/router"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>Apollo<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"apollo-angular"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> gql <span class="token keyword">from</span> <span class="token string">"graphql-tag"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>Product<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../services/products.service"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>map<span class="token punctuation">,</span> tap<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"rxjs"</span><span class="token punctuation">;</span>

@<span class="token function">Component</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
 selector<span class="token punctuation">:</span> <span class="token string">'app-products'</span><span class="token punctuation">,</span>
 imports<span class="token punctuation">:</span> <span class="token punctuation">[</span>AsyncPipe<span class="token punctuation">,</span> RouterLink<span class="token punctuation">]</span><span class="token punctuation">,</span>
 templateUrl<span class="token punctuation">:</span> <span class="token string">'./products.component.html'</span><span class="token punctuation">,</span>
 styleUrl<span class="token punctuation">:</span> <span class="token string">'./products.component.scss'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ProductsComponent</span> <span class="token punctuation">{</span>

 PRODUCTS_QUERY <span class="token operator">=</span> gql<span class="token template-string"><span class="token string">`
 {
   products {
     id
     price
     image
     title
   }
 }`</span></span>

 <span class="token keyword">private</span> readonly apollo <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span>Apollo<span class="token punctuation">)</span>

<span class="token keyword">public</span> products$ <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>apollo<span class="token punctuation">.</span>watchQuery<span class="token operator">&lt;</span><span class="token punctuation">{</span> products<span class="token punctuation">:</span> Product<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
 query<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>PRODUCTS_QUERY
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>valueChanges<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>
 <span class="token function">tap</span><span class="token punctuation">(</span>response <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'GraphQL response:'</span><span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 <span class="token function">map</span><span class="token punctuation">(</span>result <span class="token operator">=&gt;</span> result<span class="token punctuation">.</span>data<span class="token punctuation">.</span>products<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><blockquote><p>Verify that the GraphQL server is running on <a target="_blank" href="http://localhost:4000">http://localhost:4000</a>. If not, go to the server directory in the workspace and run <code class="inline-code">npm start</code>.</p></blockquote><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/server-running-4000.png?sfvrsn=1d05811_2" alt="npm run start - Server is running at http://localhost:4000/" /></p><p>Start the Angular App <code class="inline-code">ng serve</code>, navigate to <a target="_blank" href="http://localhost:4200">http://localhost:4200</a>, open the DevTools and check the browser console. You should see the logged GraphQL response with only the required fields for our UI. Yeah!!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/graphql-required-fields.png?sfvrsn=6c61a301_2" alt="Browser shows products with image, title, price" /></p><p>Yes, our Angular app is requesting data from the GraphQL Mock. If we open the DevTools in the console tab, we see two elements with only the fields from the query! No more extra or unnecessary fields.</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/console-required-fields.png?sfvrsn=37ade129_2" alt="Console shows id, image, price, title" /></p><p>Mmmm &hellip; looks fine, but for our app we want to maybe show a longer list of products while the backend continues working on other things. Let&rsquo;s improve it.</p><p>Open the <code class="inline-code">server/src/schema-mocks.ts</code>. We use <code class="inline-code">addMocksToSchema</code>, but when we don&rsquo;t specify mocks for list fields, <code class="inline-code">@graphql-tools/mock</code> returns lists with a default length of 2. That&rsquo;s the reason we see two items unless we override it with <a target="_blank" href="https://the-guild.dev/graphql/tools/docs/api/classes/mock_src.mocklist">MockList</a>.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>typeDefs<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./schema"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>makeExecutableSchema<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@graphql-tools/schema"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>addMocksToSchema<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@graphql-tools/mock"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> schema <span class="token operator">=</span> <span class="token function">makeExecutableSchema</span><span class="token punctuation">(</span><span class="token punctuation">{</span>typeDefs<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token keyword">const</span> mocks <span class="token operator">=</span> <span class="token punctuation">{</span>

 Product<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
   id<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`1`</span></span><span class="token punctuation">,</span>
   title<span class="token punctuation">:</span> <span class="token string">'Mock Product'</span><span class="token punctuation">,</span>
   price<span class="token punctuation">:</span> <span class="token number">15.2</span><span class="token punctuation">,</span>
   description<span class="token punctuation">:</span> <span class="token string">'This is a mocked product description.'</span><span class="token punctuation">,</span>
   category<span class="token punctuation">:</span> <span class="token string">'Electronics'</span><span class="token punctuation">,</span>
   image<span class="token punctuation">:</span> <span class="token string">'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_t.png'</span><span class="token punctuation">,</span>
   rating<span class="token punctuation">:</span> <span class="token punctuation">{</span>
     rate<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
     count<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>


<span class="token keyword">export</span> <span class="token keyword">const</span> schemaWithMocks <span class="token operator">=</span> <span class="token function">addMocksToSchema</span><span class="token punctuation">(</span><span class="token punctuation">{</span>schema<span class="token punctuation">,</span> mocks<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Override the Query in the products and use the <code class="inline-code">MockList</code> function to return 15 elements.</p><pre class=" language-typescript"><code class="prism  language-typescript">Query<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
 products<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">new</span> <span class="token class-name">MockList</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</code></pre><p>The final code looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>typeDefs<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./schema"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>makeExecutableSchema<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@graphql-tools/schema"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>addMocksToSchema<span class="token punctuation">,</span> MockList<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@graphql-tools/mock"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> schema <span class="token operator">=</span> <span class="token function">makeExecutableSchema</span><span class="token punctuation">(</span><span class="token punctuation">{</span>typeDefs<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token keyword">const</span> mocks <span class="token operator">=</span> <span class="token punctuation">{</span>
    Query<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
      products<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">new</span> <span class="token class-name">MockList</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 Product<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
   id<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`1`</span></span><span class="token punctuation">,</span>
   title<span class="token punctuation">:</span> <span class="token string">'Mock Product'</span><span class="token punctuation">,</span>
   price<span class="token punctuation">:</span> <span class="token number">15.2</span><span class="token punctuation">,</span>
   description<span class="token punctuation">:</span> <span class="token string">'This is a mocked product description.'</span><span class="token punctuation">,</span>
   category<span class="token punctuation">:</span> <span class="token string">'Electronics'</span><span class="token punctuation">,</span>
   image<span class="token punctuation">:</span> <span class="token string">'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_t.png'</span><span class="token punctuation">,</span>
   rating<span class="token punctuation">:</span> <span class="token punctuation">{</span>
     rate<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
     count<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">,</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>


<span class="token keyword">export</span> <span class="token keyword">const</span> schemaWithMocks <span class="token operator">=</span> <span class="token function">addMocksToSchema</span><span class="token punctuation">(</span><span class="token punctuation">{</span>schema<span class="token punctuation">,</span> mocks<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Save changes in the <code class="inline-code">schema-mocks.ts</code>, stop and start the GraphQL server. After that, we can reload the Angular app and now get 15 elements!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/angular-graphql-15-products.png?sfvrsn=51d1915_2" alt="Now the browser shows 15 items with the clean layout" /></p><p>One more thing. I want to go a step further. Now we know how to write queries and use mock data, but in the real world you won&rsquo;t work with only mock data. You must connect a real REST API with GraphQL. Let&rsquo;s do our final chapter integrating GraphQL with a REST API.</p><h2 id="integrate-graphql-with-rest-api">Integrate GraphQL with REST API</h2><p>When we built our GraphQL server to make our development process easy, we use mocks, <code class="inline-code">server/src/schema-mocks.ts</code> using <code class="inline-code">@graphql-tools/mock</code>. But to query the real data from the REST API, something needs to take the responsibility to get that information in GraphQL and these are <code class="inline-code">resolvers</code>.</p><p>The resolvers are functions that tell GraphQL how to fetch the data for a particular field in your schema. When a query is executed, GraphQL walks the query tree and calls resolver functions to produce values for each field.</p><p>If you do not provide a resolver for a field, GraphQL uses default resolvers that simply return the property of the same name from the parent object (e.g., for <code class="inline-code">Product.title</code> it returns <code class="inline-code">parent.title</code>). This works well when your data shape already matches your schema.</p><p>Create the resolver for our schema; open the file (<code class="inline-code">server/src/schema.ts</code>). Define a resolver object and implement <code class="inline-code">Query.products</code> using the <code class="inline-code">fetch</code> function to request the data from API.</p><pre class=" language-typescript"><code class="prism  language-typescript">  <span class="token keyword">export</span> <span class="token keyword">const</span> resolvers <span class="token operator">=</span> <span class="token punctuation">{</span>
    Query<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      products<span class="token punctuation">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token string">'https://fakestoreapi.com/products'</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>res<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Failed to fetch products: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>res<span class="token punctuation">.</span>status<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>res<span class="token punctuation">.</span>statusText<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Open the server/src/index.ts, it has a schema: schemaWithMocks in the ApolloServer instantiation; we&rsquo;re going to make a small change to it.</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>ApolloServer<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@apollo/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>startStandaloneServer<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@apollo/server/standalone"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>schemaWithMocks<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./schema-mock"</span><span class="token punctuation">;</span>


<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">startApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    schema<span class="token punctuation">:</span> schemaWithMocks
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span>url<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">startStandaloneServer</span><span class="token punctuation">(</span>server<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`
      Server is running at </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
  `</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">startApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>First, remove the <code class="inline-code">schema: schemaWithMocks</code> and set the <code class="inline-code">typeDef</code> and <code class="inline-code">resolvers</code> from the <code class="inline-code">schema</code> file.</p><p>The final version looks like:</p><pre class=" language-typescript"><code class="prism  language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span>ApolloServer<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@apollo/server"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>startStandaloneServer<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@apollo/server/standalone"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>typeDefs<span class="token punctuation">,</span> resolvers<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./schema"</span><span class="token punctuation">;</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">startApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
 <span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
   typeDefs<span class="token punctuation">,</span>
   resolvers<span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">const</span> <span class="token punctuation">{</span>url<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">startStandaloneServer</span><span class="token punctuation">(</span>server<span class="token punctuation">)</span><span class="token punctuation">;</span>
 console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`
     Server is running at </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
 `</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">startApolloServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Save changes and remember to stop and start the GraphQL server. After that, we can reload the Angular app connected with a REST API using GraphQL!!!</p><p><img src="https://d585tldpucybw.cloudfront.net/sfimages/default-source/blogs/2025/2025-12/angular-graphql-rest-api.png?sfvrsn=cb515c63_2" alt="Now the store shows a variety of products, all nice and cleanly laid out, only the necessary info" /></p><h2 id="recap">Recap</h2><p>This was a long journey with Angular and GraphQL. It was so fun!</p><p>We learned from the beginning why and when to use GraphQL, starting from basic GraphQL setup, mocking the server response, and how to integrate GraphQL with Angular using Apollo to make precise data-fetching, requesting the exact fields needed.</p><p>We used the power of the query to clearly show what data the component needs while the backend can evolve without breaking the frontend, as long as it supports the requested fields.</p><p>Finally, we connected GraphQL with a REST API to make real-world queries like you will in your job.</p><p>Source:</p><ul><li>Start: <a target="_blank" href="https://github.com/danywalls/graphql-and-angular/tree/graphql-server-start">https://github.com/danywalls/graphql-and-angular/tree/graphql-server-start</a></li><li>Final: <a target="_blank" href="https://github.com/danywalls/graphql-and-angular/tree/graphql-server-end">https://github.com/danywalls/graphql-and-angular/tree/graphql-server-end</a></li></ul><hr /><blockquote><p>The Kendo Store was built with ease using Progress Kendo UI for Angular components. Ready to see what you can create with Kendo UI for Angular? It comes with a 30-day free trial.</p><br /><p><a target="_blank" href="https://www.telerik.com/try/kendo-angular-ui" class="Btn">Try Now</a></p></blockquote><img src="https://feeds.telerik.com/link/23055/17227877.gif" height="1" width="1"/>]]></content>
  </entry>
</feed>
