<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mofiro Jean </title>
    <description>The latest articles on DEV Community by Mofiro Jean  (@mofirojean).</description>
    <link>https://dev.to/mofirojean</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F966237%2Faf2bd298-50dc-4391-9193-34d4a5208d6e.jpg</url>
      <title>DEV Community: Mofiro Jean </title>
      <link>https://dev.to/mofirojean</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mofirojean"/>
    <language>en</language>
    <item>
      <title>ngx-transforms: 90 standalone Angular pipes that actually compose</title>
      <dc:creator>Mofiro Jean </dc:creator>
      <pubDate>Sun, 17 May 2026 21:55:52 +0000</pubDate>
      <link>https://dev.to/mofirojean/ngx-transforms-90-standalone-angular-pipes-that-actually-compose-30fk</link>
      <guid>https://dev.to/mofirojean/ngx-transforms-90-standalone-angular-pipes-that-actually-compose-30fk</guid>
      <description>&lt;p&gt;I shipped a 90-pipe Angular library, and the thing I want to write about isn't the pipes themselves. It's what happens when you compose them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/ngx-transforms" rel="noopener noreferrer"&gt;ngx-transforms&lt;/a&gt; is a standalone Angular pipe library - 90 pipes across 8 categories, lightweight and verified against Angular 17 / 19 / 21 in CI. You can install it today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;ngx-transforms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this post isn't really a feature dump. It's about something. I noticed three categories in it: &lt;strong&gt;the pipes get more useful when they're composed than when they're used alone&lt;/strong&gt;, and Angular doesn't have a strong cultural pattern for that yet. Most pipe libraries are flat catalogs. I want to push for a different framing: pipes as a composable language for template-side data transformation.&lt;/p&gt;

&lt;p&gt;If you stick with me, by the end of this post you'll have six concrete patterns you can lift into your next Angular project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;Every Angular project I've worked on has a &lt;code&gt;pipes/&lt;/code&gt; folder that grows organically. Truncate. Time-ago. Slug from title. Mask the credit card. Format bytes. Group by region. Each one written by hand, in each codebase, with subtle bugs at the edges (what does &lt;code&gt;truncate&lt;/code&gt; do with &lt;code&gt;null&lt;/code&gt;? what about emoji? what about whitespace input to &lt;code&gt;slugify&lt;/code&gt;?).&lt;/p&gt;

&lt;p&gt;There are existing pipe libraries, but most of them are NgModule-based artifacts from the Angular 2–14 era. With standalone components stable since Angular 14 and the default since 17, the calculus changed: you can now import a single pipe class directly into a single component without polluting an NgModule. Tree-shaking works. Bundle size doesn't suffer.&lt;/p&gt;

&lt;p&gt;So I rewrote what I'd been writing by hand for years, as 90 individually-importable standalone pipes, with tests and a docs site. The library is at &lt;strong&gt;0.3.2&lt;/strong&gt; today, deliberately pre-1.0 until real-world adoption surfaces issues I can't predict from in-house testing. (More on that philosophy below.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;p&gt;8 categories, 90 pipes total:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;A taste&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;truncate&lt;/code&gt;, &lt;code&gt;slugify&lt;/code&gt;, &lt;code&gt;latinize&lt;/code&gt;, &lt;code&gt;template&lt;/code&gt;, &lt;code&gt;wrap&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Array&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;groupBy&lt;/code&gt;, &lt;code&gt;orderBy&lt;/code&gt;, &lt;code&gt;unique&lt;/code&gt;, &lt;code&gt;chunk&lt;/code&gt;, &lt;code&gt;intersection&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Math&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;average&lt;/code&gt;, &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;percentage&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Object&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;keys&lt;/code&gt;, &lt;code&gt;pairs&lt;/code&gt;, &lt;code&gt;pick&lt;/code&gt;, &lt;code&gt;omit&lt;/code&gt;, &lt;code&gt;invert&lt;/code&gt;, &lt;code&gt;diffObj&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boolean&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;isDefined&lt;/code&gt;, &lt;code&gt;isNull&lt;/code&gt;, &lt;code&gt;isString&lt;/code&gt;, &lt;code&gt;isArray&lt;/code&gt;, &lt;code&gt;isEmpty&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;count&lt;/code&gt;, &lt;code&gt;timeAgo&lt;/code&gt;, &lt;code&gt;jsonPretty&lt;/code&gt;, &lt;code&gt;device&lt;/code&gt;, &lt;code&gt;textToSpeech&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;htmlSanitize&lt;/code&gt;, &lt;code&gt;creditCardMask&lt;/code&gt;, &lt;code&gt;emailMask&lt;/code&gt;, &lt;code&gt;ipAddressMask&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Media&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;qrCode&lt;/code&gt;, &lt;code&gt;barcode&lt;/code&gt;, &lt;code&gt;gravatar&lt;/code&gt;, &lt;code&gt;colorConvert&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every pipe is a standalone class. You import it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TruncatePipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TimeAgoPipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ngx-transforms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TruncatePipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TimeAgoPipe&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;p&amp;gt;{{ post.body | truncate:80 }}&amp;lt;/p&amp;gt;
    &amp;lt;small&amp;gt;{{ post.createdAt | timeAgo }}&amp;lt;/small&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostCard&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing fancy. The interesting part starts when you stop thinking of pipes as standalone utilities and start thinking of them as a chainable language.&lt;/p&gt;

&lt;h2&gt;
  
  
  The compositional thesis
&lt;/h2&gt;

&lt;p&gt;Here's a sentence I'd put on a poster: &lt;strong&gt;Angular templates are a great place to express data transformations, and we've underused them for years.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reason is cultural, not technical. NgModules made importing pipes annoying enough that most apps imported one or two and wrote the rest as component-class getters or RxJS &lt;code&gt;map&lt;/code&gt; chains. Standalone components dissolved that friction. You can now drop three pipes into one component and chain them with no overhead.&lt;/p&gt;

&lt;p&gt;When you do that, three things become true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The transformation lives next to the markup it controls.&lt;/strong&gt; A reader sees both the shape of the data and how it renders, in one place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memoization is free.&lt;/strong&gt; Pure pipes cache by reference. Angular reuses cached results across change detection cycles automatically, no &lt;code&gt;computed()&lt;/code&gt; needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The component class shrinks.&lt;/strong&gt; Often to zero transformation logic. Just inputs, signals, and event handlers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last point is the one that surprised me. By the time I had 60+ pipes, my own components had stopped having transformation methods at all. The class became data; the template became an algorithm. Some people will find that ugly. I find it honest that the template is &lt;em&gt;already&lt;/em&gt; where transformation happens conceptually, so making it the literal place too removes a layer of indirection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six patterns I'd reach for
&lt;/h2&gt;

&lt;p&gt;The library's docs site has &lt;a href="https://ngx-transforms.vercel.app/docs/recipes" rel="noopener noreferrer"&gt;six full recipes&lt;/a&gt;, each with a live interactive playground. Here's the abbreviated tour, one pattern per pipe-composition shape.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Recursive walker for rendering unknown JSON
&lt;/h3&gt;

&lt;p&gt;You have a value of unknown shape. Render it as a tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonPipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IsArrayPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IsObjectPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PairsPipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ngx-transforms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-tree-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;JsonPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IsArrayPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IsObjectPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PairsPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// ← self-import&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    @if (value() | isArray) {
      &amp;lt;ul&amp;gt;
        @for (item of asArray(); track $index) {
          &amp;lt;li&amp;gt;&amp;lt;app-tree-node [value]="item" /&amp;gt;&amp;lt;/li&amp;gt;
        }
      &amp;lt;/ul&amp;gt;
    } @else if (value() | isObject) {
      &amp;lt;dl&amp;gt;
        @for (entry of value() | pairs; track entry[0]) {
          &amp;lt;dt&amp;gt;{{ entry[0] }}&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;&amp;lt;app-tree-node [value]="entry[1]" /&amp;gt;&amp;lt;/dd&amp;gt;
        }
      &amp;lt;/dl&amp;gt;
    } @else {
      &amp;lt;span&amp;gt;{{ value() | json }}&amp;lt;/span&amp;gt;
    }
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;asArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three pipes (&lt;code&gt;isArray&lt;/code&gt;, &lt;code&gt;isObject&lt;/code&gt;, &lt;code&gt;pairs&lt;/code&gt;) and a self-importing standalone component. The whole walker is the template. No class methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Sequential chain to slug from any title
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;/blog/{{ title | truncate:60:'':true | latinize | slugify }}&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Truncate first to preserve word boundaries while spaces still exist, latinize to flatten diacritics to ASCII, slugify to lowercase and replace whitespace. Order matters. The chain reads top-to-bottom like a pipeline diagram.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Parallel fan-out — KPI dashboard
&lt;/h3&gt;

&lt;p&gt;One source array, six independent aggregations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ orders | sum:'total' | currency }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ orders | average:'total' | currency }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ orders | max:'total' | currency }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ orders | sum:'fileSizeBytes' | bytes }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ orders | pluck:'customer' | unique | count }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ completed | percentage:orders.length:1 }}%&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure pipes memoize per chain. The six cards don't recompute unless the input array reference changes and even then, only chains depending on the changed data re-run. &lt;strong&gt;You don't pay for the cards you don't visually update.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Conditional substitution for avatar fallback
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (!(user.email | isEmpty)) {
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;[src]=&lt;/span&gt;&lt;span class="s"&gt;"user.email | gravatar:64"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
} @else if (!(user.name | isEmpty)) {
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"initials"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ user.name | initials }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
} @else {
  &lt;span class="nt"&gt;&amp;lt;icon&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;isEmpty&lt;/code&gt; gates each branch. &lt;code&gt;gravatar&lt;/code&gt; and &lt;code&gt;initials&lt;/code&gt; handle their respective renders. Adding a fourth fallback (say, a per-tenant company logo) is one &lt;code&gt;@else if&lt;/code&gt; block  no class changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Scan-and-transform for PII leak detection
&lt;/h3&gt;

&lt;p&gt;Extract sensitive patterns from unstructured text, render each detection through its mask pipe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Cards ({{ (text | match:cardRe).length }})&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  @for (card of text | match:cardRe; track $index) {
    &lt;span class="nt"&gt;&amp;lt;code&amp;gt;&lt;/span&gt;{{ card | creditCardMask }}&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt;
  }
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Emails ({{ (text | match:emailRe).length }})&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  @for (email of text | match:emailRe; track $index) {
    &lt;span class="nt"&gt;&amp;lt;code&amp;gt;&lt;/span&gt;{{ email | emailMask }}&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt;
  }
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detection regex says &lt;em&gt;what to find&lt;/em&gt;. Mask pipe says &lt;em&gt;how to redact&lt;/em&gt;. They evolve independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Diff-driven UI for dirty-form tracking
&lt;/h3&gt;

&lt;p&gt;One signal holds the original snapshot, another holds the live edits. One pipe expression answers every dirty-state question the UI has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;pre&amp;gt;&lt;/span&gt;{{ current() | diffObj:original() | json }}&lt;span class="nt"&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[disabled]=&lt;/span&gt;&lt;span class="s"&gt;"(current() | diffObj:original()) | isEmpty"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Save changes
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That diff object IS the PATCH body. Send it as-is to your API. On save success, promote &lt;code&gt;current&lt;/code&gt; → &lt;code&gt;original&lt;/code&gt; and the form goes clean automatically. No dirty flags, no reducers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering choices worth talking about
&lt;/h2&gt;

&lt;p&gt;A few things that turned out matter more than I expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tree-shaking, verified
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sideEffects: false&lt;/code&gt; in the published &lt;code&gt;package.json&lt;/code&gt;. Every pipe is a standalone class with no top-level side effects. Modern bundlers tree-shake by default. The library ships as a single FESM bundle at &lt;strong&gt;168 KB raw / 27.9 KB gzipped / 23.3 KB brotli&lt;/strong&gt; that's the &lt;em&gt;whole thing&lt;/em&gt;. Real consumer apps include only the pipes they import, plus the deps those pipes actually need.&lt;/p&gt;

&lt;p&gt;Three pipes do pull their own deps and are worth flagging if you care about size: &lt;code&gt;qrCode&lt;/code&gt; (qrcode), &lt;code&gt;barcode&lt;/code&gt; (jsbarcode), &lt;code&gt;gravatar&lt;/code&gt; (js-md5), &lt;code&gt;asciiArt&lt;/code&gt; (ts-ascii-engine). The other 86 pipes are pure standalone-pipe code.&lt;/p&gt;

&lt;p&gt;Bundle size is enforced in CI via &lt;code&gt;size-limit&lt;/code&gt; because every PR runs against fixed thresholds. Regressions fail the build.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-version Angular CI
&lt;/h3&gt;

&lt;p&gt;Claiming "supports Angular 17–21" is cheap; verifying it is the work. A nightly cron in GitHub Actions scaffolds a fresh &lt;code&gt;ng new&lt;/code&gt; project at each of Angular 17, 19, and 21, installs the locally-packed library tarball, and runs &lt;code&gt;ng build&lt;/code&gt;. If any version breaks, the matrix reports red within 24 hours. That's how you find out the AOT compiler tightened a check between 19 and 20 &lt;em&gt;before&lt;/em&gt; a user files an issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type narrowing throughout
&lt;/h3&gt;

&lt;p&gt;Every pipe's &lt;code&gt;transform()&lt;/code&gt; signature is &lt;code&gt;(value: unknown, ...args)&lt;/code&gt; (or a tighter type when it makes sense). No &lt;code&gt;any&lt;/code&gt;. The pipes do runtime guards for null/undefined/wrong-type input and degrade to sensible defaults instead of throwing. That mismatch between TypeScript's compile-time narrowing and JavaScript's runtime reality is where most pipe libraries get sloppy; this one tries hard not to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deliberately pre-1.0
&lt;/h3&gt;

&lt;p&gt;The library is at 0.3.2. I'm not in a hurry to cut 1.0.&lt;/p&gt;

&lt;p&gt;Here's the reasoning: 1.0 is a promise about API stability under real-world pressure, not an internal "we feel ready" signal. Plenty of libraries have shipped 1.0 prematurely and either had to ship 1.x with breaking changes (eroding trust) or sat frozen at 1.x while everyone migrated to 2.x. I'd rather absorb the discovery period in 0.x where breaking changes are still socially expected.&lt;/p&gt;

&lt;p&gt;The 1.0 trigger isn't a calendar date. It's a signal pattern: real consumers reporting non-trivial issues that I fix, a handful of stars, weekly npm downloads in the hundreds, a stretch of weeks without breaking changes. When that emerges organically, the version bump just acknowledges what's already true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pure pipes + Signals: The Underrated Combo
&lt;/h2&gt;

&lt;p&gt;A practical note for anyone using signals (you should be, in new code).&lt;/p&gt;

&lt;p&gt;Pure pipes and signals are weirdly complementary. The signal triggers change detection when its value changes; the pipe memoizes the transformation result keyed off the input reference. The net effect is that a derived view defined as &lt;code&gt;mySignal() | someChain | json&lt;/code&gt; recomputes precisely when it needs to and not a moment more without you writing a single &lt;code&gt;computed()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the &lt;em&gt;real&lt;/em&gt; reason I think pipes are due for a comeback. Signals fixed Angular's reactivity story, and pure pipes are the lightweight derived-value mechanism that pairs with signals. &lt;code&gt;computed()&lt;/code&gt; is great for class-level derived values; pipes are great for template-level ones. Use the right tool for the surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it / contribute
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docs + live playground:&lt;/strong&gt; &lt;a href="https://ngx-transforms.vercel.app" rel="noopener noreferrer"&gt;ngx-transforms.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;code&gt;npm install ngx-transforms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source / issues:&lt;/strong&gt; &lt;a href="https://github.com/mofirojean/ngx-transforms" rel="noopener noreferrer"&gt;github.com/mofirojean/ngx-transforms&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find a pipe missing, a recipe pattern that should be documented, or a real bug, please file an issue. The discovery period that gates 1.0 lives or dies on real consumer feedback, so even a "I tried to do X and got confused" is genuinely useful.&lt;/p&gt;

&lt;p&gt;If you write Angular and want pipes that compose, you have 90 of them now. Six recipes worth of patterns to lift directly. And a maintainer (me) who'd rather hear what's wrong than guess.&lt;/p&gt;

&lt;p&gt;Build something with it. Let me know what breaks.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Getting started with Angular</title>
      <dc:creator>Mofiro Jean </dc:creator>
      <pubDate>Mon, 24 Mar 2025 13:32:00 +0000</pubDate>
      <link>https://dev.to/ngcameroon/getting-started-with-angular-fb5</link>
      <guid>https://dev.to/ngcameroon/getting-started-with-angular-fb5</guid>
      <description>&lt;p&gt;&lt;a href="https://angular.dev" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; is one of the coolest frameworks around for building dynamic web apps. Whether you’re totally new to web development or switching over from another framework, this guide will get you started with Angular quickly and have a bit of fun along the way!&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s in Store:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What is Angular?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting Up Your Angular Playground&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creating Your First Angular Project&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Getting to Know Your Angular App&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running Your App Locally&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1. What’s Angular All About?
&lt;/h3&gt;

&lt;p&gt;Angular is a framework by Google for building single-page applications (SPAs) using HTML, CSS, and TypeScript. It’s a modern take on web development that makes building complex apps a breeze. Here are some fun features you’ll love:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two-way Data Binding:&lt;/strong&gt; Keeps your data and UI in perfect sync—magic!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Injection:&lt;/strong&gt; Helps you organize and test your code with ease.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular CLI:&lt;/strong&gt; A powerful command-line tool that makes setting up and managing your project super simple.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Setting Up Your Angular Playground
&lt;/h3&gt;

&lt;p&gt;Before you dive into coding, you need to set up your environment. Here’s how to get started:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install Node.js and npm&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Angular runs on Node.js. Download it from &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;nodejs.org&lt;/a&gt;. Installing Node.js also gets you npm, which is like your app’s personal assistant for managing dependencies.&lt;/p&gt;

&lt;p&gt;Open your terminal and check your installation with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gzqw2ao0v5zxww6o3rp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gzqw2ao0v5zxww6o3rp.png" alt="Version for Node and npm" width="544" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Install Angular CLI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Angular CLI is your best buddy for Angular development. Install it globally with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @angular/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, make sure it’s working by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1z2lg7diiujqxwltg1d4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1z2lg7diiujqxwltg1d4.png" alt="Angular version on ubuntu terminal" width="757" height="445"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Creating Your First Angular Project
&lt;/h3&gt;

&lt;p&gt;Now for the fun part—building your very first Angular app!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Generate a New Project&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use Angular CLI to kick off a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new my-first-angular-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll get a couple of quick prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which stylesheet format?&lt;/strong&gt; Choose “CSS” to keep things simple.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)?&lt;/strong&gt; Choose “No”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsm668h1bt9hsrm537fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdsm668h1bt9hsrm537fx.png" alt="Generated files following the creation of an Angular project using the  raw `ng new command` endraw " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Step Into Your Project&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Change into your project’s folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-first-angular-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Launch Your App&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Fire up the development server with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmojbtmtiwa0qck1fcstv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmojbtmtiwa0qck1fcstv.png" alt="Successful bundling of our angular application" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your browser and visit &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt; to see your shiny new app in action!&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Getting to Know Your Angular App
&lt;/h3&gt;

&lt;p&gt;After creating your Angular project, you'll encounter a structured set of files and folders. Let's explore the key components within the &lt;code&gt;src/app/&lt;/code&gt; directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.config.ts&lt;/code&gt;&lt;/strong&gt;: Defines the application configuration, instructing Angular on assembling the application. As you introduce more providers, declare them here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.component.ts&lt;/code&gt;&lt;/strong&gt;: Defines the root component, &lt;code&gt;AppComponent&lt;/code&gt;, which serves as the primary view in your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.component.html&lt;/code&gt;&lt;/strong&gt;: The HTML template associated with &lt;code&gt;AppComponent&lt;/code&gt;, where you design the user interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.component.css&lt;/code&gt;&lt;/strong&gt;: Contains the CSS styles specific to &lt;code&gt;AppComponent&lt;/code&gt;, allowing for component-level styling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.component.spec.ts&lt;/code&gt;&lt;/strong&gt;: Provides unit tests for &lt;code&gt;AppComponent&lt;/code&gt; to ensure its functionality remains intact during development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;app.routes.ts&lt;/code&gt;&lt;/strong&gt;: Defines the application's routing configuration, mapping URL paths to components.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these files is crucial, as they form the backbone of your Angular application, enabling you to build, configure, and style your app effectively. For more information on the functions of the various files and directories, checkout &lt;a href="https://angular.dev/reference/configs/file-structure#workspace-configuration-files" rel="noopener noreferrer"&gt;workspace configuration files&lt;/a&gt; in an Angular app.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Running and Enjoying Your Angular App
&lt;/h3&gt;

&lt;p&gt;Anytime you want to work on your app, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re feeling adventurous and want to change the port, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve &lt;span class="nt"&gt;--port&lt;/span&gt; 4300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server reloads your app automatically whenever you make changes—so you can see your progress instantly!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedjlomy97nod0wlemnfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedjlomy97nod0wlemnfd.png" alt="Our served angular app application on the browser" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;Now that you’ve set up and run your first Angular project, you’re ready to dive deeper.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create More Components:&lt;/strong&gt; Build custom parts of your UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Master Data Binding:&lt;/strong&gt; Learn how to make your data and view work together seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore Services and APIs:&lt;/strong&gt; Discover how to fetch and manage data from external sources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Angular is a powerful tool, and with its amazing CLI and organised structure, you’re well on your way to building stunning web applications—whether it’s a simple site or a complex enterprise app. Stay tuned for more fun tutorials as you continue your Angular adventure!&lt;/p&gt;




&lt;p&gt;Happy coding, and have fun exploring Angular 🚀.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webcomponents</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
