<?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>Forem: Dzhavat Ushev</title>
    <description>The latest articles on Forem by Dzhavat Ushev (@dzhavat).</description>
    <link>https://forem.com/dzhavat</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%2F184225%2F2a89dd2e-8b58-4c7b-8238-d1ba14be309d.jpg</url>
      <title>Forem: Dzhavat Ushev</title>
      <link>https://forem.com/dzhavat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dzhavat"/>
    <language>en</language>
    <item>
      <title>Change the position of Command Palette and Quick Inputs panels in VS Code</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Fri, 07 Feb 2025 14:56:56 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/change-the-position-of-command-palette-and-quick-inputs-panels-in-vs-code-31gi</link>
      <guid>https://forem.com/playfulprogramming/change-the-position-of-command-palette-and-quick-inputs-panels-in-vs-code-31gi</guid>
      <description>&lt;p&gt;VS Code released the &lt;a href="https://code.visualstudio.com/updates/v1_97" rel="noopener noreferrer"&gt;January 2025 (v1.97)&lt;/a&gt; release yesterday, and it’s again packed with a lot of good stuff. One small but welcome change is that &lt;a href="https://code.visualstudio.com/updates/v1_97/#_move-the-command-palette-and-quick-inputs" rel="noopener noreferrer"&gt;the position&lt;/a&gt; of the Command Palette and Quick Inputs panels can be customized! Who doesn’t love customization, right?&lt;/p&gt;

&lt;p&gt;Until now these panels always opened at the top. You can reposition them now. There are a few options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top&lt;/li&gt;
&lt;li&gt;Center&lt;/li&gt;
&lt;li&gt;Custom position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can set the position via the “Customize Layout” picker in the top bar, or you can open one of the panels and start dragging it around. The new position will persist accross reloads.&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%2F80qaaa0acu2hlws2sy0n.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%2F80qaaa0acu2hlws2sy0n.png" alt="“Customize Layout” panel in VS Code" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading. Hope you learned something new. See you in another post 😊&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Downloading the same file 102+ times</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Wed, 08 Jan 2025 21:23:14 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/downloading-the-same-file-102-times-3ood</link>
      <guid>https://forem.com/playfulprogramming/downloading-the-same-file-102-times-3ood</guid>
      <description>&lt;p&gt;Have YOU ever tried downloading the same file 102+ times in your favorite browser? Do you know what happens on the 102nd time? 🙃&lt;/p&gt;

&lt;p&gt;I do. The answer is ... it depends 😋 It varies between browsers and it’s a bit of a surprise.&lt;/p&gt;

&lt;p&gt;Before I show you the screenshots, let me first tell you a short story about how I ended up in the &lt;em&gt;“lets-download-this-file-102-times”&lt;/em&gt; rabbit hole so bear with me.&lt;/p&gt;

&lt;p&gt;I work as a software developer and one day I got a message from a colleague asking something about a new feature. She sent me a link to an issue. There was a screenshot that caught my attention. It looked very much like the one below.&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%2Fm7j9bf4e7isba9hzuyvf.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%2Fm7j9bf4e7isba9hzuyvf.png" alt="List of recently downloaded files similar to the screenshot in our project" width="530" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the time the file’s name was hardcoded to &lt;em&gt;“Report.zip”&lt;/em&gt;. So seeing &lt;em&gt;“Report.zip”&lt;/em&gt;, &lt;em&gt;“Report (1).zip”&lt;/em&gt; or &lt;em&gt;“Report (42).zip”&lt;/em&gt; was to be expected. Instead of a counter, I was suprised to see a timestamp. Where did that come from? It was absolutely not in the code. My colleague didn’t manually add it either. Something was not right. And from here on the rabbit hole got deeper and deeper. 🐰&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“A browser setting!”&lt;/em&gt; - I thought. It was rulled out quite quickly because she didn’t remember changing any settings. We were looking in Edge because that’s the browser she uses. Besides, such a setting does not exist, I later found out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Well, then maybe the browser added it automatically. But at what point?”&lt;/em&gt; I started searching on Google, going through different web pages, StackOverflow posts and forums. The more I searched, the more curious I became to figure this out. Then finally - FINALLY - &lt;a href="https://www.reddit.com/r/techsupport/comments/t49u0p/comment/jgldchp/" rel="noopener noreferrer"&gt;a reply to a Reddit post&lt;/a&gt; gave me a pretty strong hint.&lt;/p&gt;

&lt;p&gt;But was that still the case? There was only one way to find out. 🚀&lt;/p&gt;

&lt;p&gt;Fired up Edge and started downloading.&lt;/p&gt;

&lt;p&gt;1, 2, 3, ... 10, ... 42, ... 99 times.&lt;/p&gt;

&lt;p&gt;Then something magical 🪄 happened the 102nd time! Instead of bumping a number, Edge added a timestamp 😯 Bingo! 🎉 The mystery was solved. That explained it.&lt;/p&gt;

&lt;p&gt;So to make this more scientific, and for the purpose of this post, I decided to repeat the exercise in other browsers. Here are some screenshots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge
&lt;/h3&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%2F85kfcntccavv62raz8tw.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%2F85kfcntccavv62raz8tw.png" alt="Downloading the same file 102+ times in Edge" width="786" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Chrome
&lt;/h3&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%2F249jsuw3lmritxmnag72.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%2F249jsuw3lmritxmnag72.png" alt="Downloading the same file 102+ times in Chrome. Same as Edge" width="705" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Firefox
&lt;/h3&gt;

&lt;p&gt;Firefox just continues with bumping the counter. No timestamp here. Also note that there’s no space between the file’s name and the counter in parenthesis, as is the case in Edge/Chrome.&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%2Fyqmb8h89ge1op48sntkl.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%2Fyqmb8h89ge1op48sntkl.png" alt="Downloading the same file 102+ times in Firefox" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Update 2025-01-14
&lt;/h3&gt;

&lt;p&gt;After publishing this post I got curious about the behaviour in Edge/Chrome. Since both browsers are Chromium-based, which is open source, I could, in theory, just look it up in the code. I didn’t know what to look for. So I &lt;a href="https://bsky.app/profile/dzhavat.bsky.social/post/3lfngxmjkzs2f" rel="noopener noreferrer"&gt;asked on Bluesky&lt;/a&gt;. Kevin Doyon &lt;a href="https://bsky.app/profile/kevindoyon.com/post/3lfnkc5rr5s2g" rel="noopener noreferrer"&gt;replied with a link&lt;/a&gt; to a method which is responsible for generating a unique filename. Using the &lt;a href="https://github.com/chromium/chromium/blame/f48040f342e02408247e2d0644326380e1d08154/components/download/internal/common/download_path_reservation_tracker.cc#L157" rel="noopener noreferrer"&gt;“Blame”&lt;/a&gt; button at the top of the file revealed where each line of code came from. That led me to &lt;a href="https://github.com/chromium/chromium/commit/e40c631a5f311d449e8c6e136f0d70e5d548b987" rel="noopener noreferrer"&gt;this commit&lt;/a&gt; which describes why the timestamp is added to the filename.&lt;/p&gt;

&lt;p&gt;Seems like this is the end of it. Finally peace 🕊️&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%2Fwktnqpqavpouvgo6y0ax.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%2Fwktnqpqavpouvgo6y0ax.png" alt="Commit description explaining why timestamp is used in filename" width="575" height="245"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;What a TIL!&lt;/p&gt;

&lt;p&gt;Thanks for reading thus far. Hope you learned something new. See you in another post 😊&lt;/p&gt;




&lt;p&gt;P.S. If you want to try it yourself, I’ve prepared &lt;a href="https://dzhavat.github.io/assets/other/empty.zip" rel="noopener noreferrer"&gt;a zip with an empty text file&lt;/a&gt;. Go ahead and download it. 102 times, of course.&lt;/p&gt;

&lt;p&gt;Or you can quickly put together a simple demo by linking to a local file.&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;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"./fancy.zip"&lt;/span&gt; &lt;span class="na"&gt;download&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Download&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>todayilearned</category>
      <category>browser</category>
    </item>
    <item>
      <title>Creating an empty commit in Git</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Sun, 31 Mar 2024 14:00:00 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/creating-an-empty-commit-in-git-2iec</link>
      <guid>https://forem.com/playfulprogramming/creating-an-empty-commit-in-git-2iec</guid>
      <description>&lt;p&gt;Does this sounds familiar - a Continuous integration (CI) pipeline is stuck and you need to push a new commit to restart it?&lt;/p&gt;

&lt;p&gt;So now you’re looking for a place where you can make a dummy change like deleting/adding an empty line, adding/deleting a dot in a comment - any change, so you can make a new commit and push it upstream.&lt;/p&gt;

&lt;p&gt;“There must be a way to create empty commits” you tell yourself but you’re too busy looking for a place to make that dummy change instead of searching for a solution to your problem.&lt;/p&gt;

&lt;p&gt;Well, there is a better way!&lt;/p&gt;

&lt;p&gt;Git allows you to create an empty commit by simply adding the &lt;code&gt;--allow-empty&lt;/code&gt; flag to the &lt;code&gt;commig&lt;/code&gt; command. Here 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: empty commit"&lt;/span&gt; &lt;span class="nt"&gt;--allow-empty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your job is done. 🎉&lt;/p&gt;

&lt;p&gt;Thanks for reading. See you in the next post 😎&lt;/p&gt;




&lt;p&gt;Thanks to my colleague &lt;a href="https://twitter.com/mvhmimo" rel="noopener noreferrer"&gt;Morten Hansen&lt;/a&gt; for showing me this tip.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@katetrysh?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Kate Trysh&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/white-printer-paper-WX5jK0BT5JQ?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Incremental migration to Angular’s new control flow syntax</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Wed, 28 Feb 2024 20:49:02 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/incremental-migration-to-angulars-new-control-flow-syntax-j36</link>
      <guid>https://forem.com/playfulprogramming-angular/incremental-migration-to-angulars-new-control-flow-syntax-j36</guid>
      <description>&lt;p&gt;Angular v17 introduced &lt;a href="https://blog.angular.io/meet-angulars-new-control-flow-a02c6eee7843" rel="noopener noreferrer"&gt;a new control flow syntax&lt;/a&gt; that is built into the framework. The new syntax is about so-called “blocks” which are available in the template out of the box - meaning you don’t have to import anything to use them. These blocks are &lt;code&gt;@if&lt;/code&gt;, &lt;code&gt;@else if&lt;/code&gt;, &lt;code&gt;@else&lt;/code&gt;, &lt;code&gt;@for&lt;/code&gt;, &lt;code&gt;@empty&lt;/code&gt;, &lt;code&gt;@switch&lt;/code&gt;, &lt;code&gt;@case&lt;/code&gt; and &lt;code&gt;@default&lt;/code&gt;. I’m not going to explain them in details here. You can read more about each block in the &lt;a href="https://angular.io/guide/control_flow" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The new syntax is currently in developer preview. Once it becomes stable, it’ll most likely become the recommended way to handle control flow in the template, thus deprecating the &lt;code&gt;NgIf&lt;/code&gt;, &lt;code&gt;NgFor&lt;/code&gt; and &lt;code&gt;NgSwitch&lt;/code&gt; directives.&lt;/p&gt;

&lt;p&gt;But despair not! Both options will be available for at least a few major versions, so nothing is going away overnight. You have planty of time to plan the migration.&lt;/p&gt;

&lt;p&gt;Speaking of which, the Angular team has an official schematic to help you migrate 🎉&lt;/p&gt;

&lt;p&gt;It’s also quite easy to run ...&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="c"&gt;# Using Angular CLI&lt;/span&gt;
ng g @angular/core:control-flow

&lt;span class="c"&gt;# Using Nx&lt;/span&gt;
nx g @angular/core:control-flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command proceeds to ask for a path to be migrated. The default is &lt;code&gt;./&lt;/code&gt; (root) but you can set it to whatever you want. &lt;strong&gt;So you can either migrate the whole workspace at once or incrementally — step-by-step — one folder, feature or domain at a time.&lt;/strong&gt;&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%2Fjzvb3l7ln1bo24cyb5hz.jpg" 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%2Fjzvb3l7ln1bo24cyb5hz.jpg" alt="Angular schematic to migrate to the new control flow syntax" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The schematic works amazingly well but you should absolutely go through the changes afterwards to be sure that everything is at it should.&lt;/p&gt;

&lt;p&gt;Now go ahead and start using the new syntax. It’s great, I promise.&lt;/p&gt;

&lt;p&gt;Thanks for reading. See you in the next post 😎&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@nadineshaabana?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Nadine Shaabana&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/red-sony-ps-dualshock-4-YsPnamiHdmI?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Lazy-loading the animations package in Angular</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Mon, 08 Jan 2024 22:19:16 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/lazy-loading-the-animations-package-in-angular-6c6</link>
      <guid>https://forem.com/playfulprogramming-angular/lazy-loading-the-animations-package-in-angular-6c6</guid>
      <description>&lt;p&gt;We recently upgraded Angular to v17 at work. One of the first things we did after the upgrade was to lazy-load the animations package. This shaved 62.48 kB (16.51 kB gzipped) off off the &lt;code&gt;main&lt;/code&gt; bundle. Not bad for changing two lines of code!&lt;/p&gt;

&lt;p&gt;Here’s how to do it in your app:&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&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;provideAnimations&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/platform-browser/animations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&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;provideAnimationsAsync&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/platform-browser/animations/async&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;   &lt;span class="nf"&gt;provideAnimations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="nf"&gt;provideAnimationsAsync&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;// ...,&lt;/span&gt;

    &lt;span class="c1"&gt;// to disable animations&lt;/span&gt;
    &lt;span class="c1"&gt;// provideAnimationsAsync("noop"),&lt;/span&gt;
&lt;span class="p"&gt;});&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%2Fi6ztv12s6b475x8d1159.jpg" 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%2Fi6ztv12s6b475x8d1159.jpg" alt="Production build - Angular animations moved to a lazy chunk" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The 1.75 MB &lt;code&gt;main&lt;/code&gt; bundle (😱) is a story for another day 😊&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Done with the changes already? Nice! Should we call it a day? Well, .. not so fast!&lt;/p&gt;

&lt;p&gt;Lazy-loading the animations comes with a couple of side-effects!&lt;/p&gt;

&lt;p&gt;The main one is that during bootstrap, animations will not be applied until after the package has loaded. The second one is that you must remember to only import from &lt;code&gt;@angular/animation&lt;/code&gt; in lazy-loaded components. Importing anything from &lt;code&gt;@angular/animation&lt;/code&gt; in an eagerly-loaded component will disable the lazy-loading of this package.&lt;/p&gt;

&lt;p&gt;If you want to learn more about the side-effects, how to check if lazy-loading works correctly, and how this feature was implemented, check out this &lt;a href="https://riegler.fr/blog/2023-10-04-animations-async#current-implementation" rel="noopener noreferrer"&gt;excellent post&lt;/a&gt; from Matthieu Riegler.&lt;/p&gt;

&lt;p&gt;See you in the next post 🙂&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@lejo?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Elly Johnson&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/yellow-load-here-signage-bbrkZnqNbmk?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Lint rule for self-closing tags in Angular</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Mon, 13 Nov 2023 17:09:25 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/lint-rule-for-self-closing-tags-in-angular-4529</link>
      <guid>https://forem.com/playfulprogramming-angular/lint-rule-for-self-closing-tags-in-angular-4529</guid>
      <description>&lt;p&gt;Self-closing tags were introduced in &lt;a href="https://github.com/angular/angular/blob/main/CHANGELOG.md#compiler-17" rel="noopener noreferrer"&gt;Angular v15.1&lt;/a&gt;. This added a small but welcomed improvement to the developer experience (DX) when working with components. This feature allows us to use self-closing tag syntax for components without content or components where the content might be optional.&lt;/p&gt;

&lt;p&gt;As a refresher, the self-closing tag syntax looks like this:&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="c"&gt;&amp;lt;!-- Normal syntax --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-component&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Self-closing tag syntax --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-component&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;After upgrading to Angular v15.1 at work, we started using the self-closing tag syntax here and there but not consistently. There wasn’t really a way to enforce it with a tool, so it was up to the developer to remember it.&lt;/p&gt;

&lt;p&gt;Until I recently discovered that &lt;a href="https://github.com/angular-eslint/angular-eslint" rel="noopener noreferrer"&gt;angular-eslint&lt;/a&gt; had added a new lint rule in &lt;a href="https://github.com/angular-eslint/angular-eslint/releases/tag/v16.2.0" rel="noopener noreferrer"&gt;v16.2&lt;/a&gt; called &lt;a href="https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-self-closing-tags.md" rel="noopener noreferrer"&gt;&lt;code&gt;prefer-self-closing-tags&lt;/code&gt;&lt;/a&gt; that can be used to enforce this syntax partially or throughout a project.&lt;/p&gt;

&lt;p&gt;Since we had the &lt;code&gt;angular-eslint&lt;/code&gt; package already in our &lt;code&gt;package.json&lt;/code&gt;, the configuration was as simple as adding the rule to an ESLint config file.&lt;/p&gt;

&lt;p&gt;A couple of things worth mentioning about our project setup is that we have a monorepo managed by &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx&lt;/a&gt;, where we have two main apps and more than hundred libs (all of which have their own ESLint configs that inherit from root). We ended up adding the lint rule to the root ESLint config.&lt;/p&gt;

&lt;p&gt;The configuration itself ended up like this:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;files&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*.component.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;extends&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugin:@nx/angular-template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rules&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular-eslint/template/prefer-self-closing-tags&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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="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;The &lt;code&gt;*.component.html&lt;/code&gt; pattern used in the &lt;code&gt;files&lt;/code&gt; array is intentionally like that because we wanted to only target the templates of Angular components and not “regular” HTML files.&lt;/p&gt;

&lt;p&gt;Every Angular project has a main &lt;code&gt;index.html&lt;/code&gt; that is a regular HTML file where a top-level Angular component is included, i.e. &lt;code&gt;&amp;lt;my-app&amp;gt;&amp;lt;/my-app&amp;gt;&lt;/code&gt;. Writing &lt;code&gt;&amp;lt;my-app /&amp;gt;&lt;/code&gt; here would mean invalid HTML according to the specification because custom components, which Angular components are, cannot be self-closing. So the pattern above aims to avoid that file from being checked for self-closing tags.&lt;/p&gt;

&lt;p&gt;But how are self-closing tags still allowed in the Angular components? Wouldn’t that be invalid too? Well, the Angular compiler still transforms them to their normal syntax during build. So writing &lt;code&gt;&amp;lt;my-component /&amp;gt;&lt;/code&gt; becomes &lt;code&gt;&amp;lt;my-component&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/code&gt; after build.&lt;/p&gt;

&lt;p&gt;Another thing you probably noticed is that the pattern ends with &lt;code&gt;.html&lt;/code&gt;. This targets HTML files but what about inline templates? No worries! Even though the pattern specifically targets HTML files, &lt;code&gt;angular-eslint&lt;/code&gt; checks for self-closing tags in inline templates too.&lt;/p&gt;

&lt;p&gt;The best part about this lint rule is that it supports autofix. This means that - after adding the config - you can run your lint command with a &lt;code&gt;--fix&lt;/code&gt; flag. &lt;code&gt;angular-eslint&lt;/code&gt; will find all places where self-closing tags can be used, then it will fix your code automatically. You only need to review the changes. Awesome!&lt;/p&gt;

&lt;p&gt;If you’re using Prettier in your project, make sure to be on &lt;a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#283" rel="noopener noreferrer"&gt;v2.8.2&lt;/a&gt; (or later) so Prettier also formats self-closing components correctly.&lt;/p&gt;

&lt;p&gt;Self-closing tags in Angular improve the DX by allowing us to write less code. Let Angular do the rest for you.&lt;/p&gt;

&lt;p&gt;You now know how to enforce self-closing tags in your Angular project using ESLint. Go ahead and start using them.&lt;/p&gt;

&lt;p&gt;See you in the next post 🙂&lt;/p&gt;




&lt;p&gt;Thanks to &lt;a href="https://www.linkedin.com/in/larsgbn/" rel="noopener noreferrer"&gt;Lars Gyrup Brink Nielsen&lt;/a&gt; for reviewing the post.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@olloweb" rel="noopener noreferrer"&gt;Agence Olloweb&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/magnifying-glass-near-gray-laptop-computer-d9ILr-dbEdg" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>eslint</category>
    </item>
    <item>
      <title>“ViewEncapsulation” in Angular</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Tue, 03 Oct 2023 12:14:19 +0000</pubDate>
      <link>https://forem.com/dzhavat/viewencapsulation-in-angular-1mgg</link>
      <guid>https://forem.com/dzhavat/viewencapsulation-in-angular-1mgg</guid>
      <description>&lt;p&gt;Ah, &lt;a href="https://angular.io/api/core/ViewEncapsulation" rel="noopener noreferrer"&gt;&lt;code&gt;ViewEncapsulation&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;It’s what keeps you asleep through the night! Or does it? 😊&lt;/p&gt;

&lt;p&gt;Let’s refresh our knowledge about &lt;code&gt;ViewEncapsulation&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ViewEncapsulation.Emulated&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;By default, all Angular components come with something called “style encapsulation”. It means that a component “encapsulates” its own styles so they &lt;strong&gt;only&lt;/strong&gt; apply to elements within its scope. Styles defined in one component will &lt;strong&gt;not&lt;/strong&gt; have an effect on the elements in another component.&lt;/p&gt;

&lt;p&gt;Angular achieves this by &lt;em&gt;adding a specific attribute to the component’s host element and applying the same attribute to all the CSS selectors provided via &lt;code&gt;Component#styles&lt;/code&gt; or &lt;code&gt;Component#styleUrls&lt;/code&gt;.&lt;/em&gt; (taken from Angular’s docs)&lt;/p&gt;

&lt;p&gt;Considering a component to be an independent unit, this is the expected behaviour. You don’t want your components to “leak” styles that affect “outside” elements.&lt;/p&gt;

&lt;p&gt;The above is done by setting the &lt;code&gt;Component.encapsulation&lt;/code&gt; option to &lt;code&gt;ViewEncapsulation.Emulated&lt;/code&gt; (or not setting it at all since that’s the default value).&lt;/p&gt;

&lt;p&gt;Looking at the DevTools in the Figure 1 below, you can see that the &lt;code&gt;my-app&lt;/code&gt; component has a &lt;code&gt;_nghost-ng-&amp;lt;id&amp;gt;&lt;/code&gt; attribute. The same &lt;code&gt;&amp;lt;id&amp;gt;&lt;/code&gt; is also added to the &lt;code&gt;_ngcontent-ng-&amp;lt;id&amp;gt;&lt;/code&gt; attribute present on all child elements.&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%2Fck32vtip2vbr1izk6r9d.jpg" 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%2Fck32vtip2vbr1izk6r9d.jpg" alt="ViewEncapsulation.Emulated in Angular" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the &lt;code&gt;&amp;lt;id&amp;gt;&lt;/code&gt; is auto-generated by Angular and you should not rely on it being the same every time. So don’t style elements with &lt;code&gt;_ngcontent-ng-abc123&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ViewEncapsulation.None&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;View encapsulation can be turned off on a component by setting the &lt;code&gt;Component.encapsulation&lt;/code&gt; option to &lt;code&gt;ViewEncapsulation.None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But beware! Turning view encapsulation off means that all of the component’s styles now apply globally. They will no longer be scoped to the component, and can therefore affect any HTML element in the application.&lt;/p&gt;

&lt;p&gt;You can see that by inspecting the component’s elements in DevTools.&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%2Fkoxbfhk738nshd1dp8f8.jpg" 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%2Fkoxbfhk738nshd1dp8f8.jpg" alt="ViewEncapsulation.None in Angular" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 2 above shows us that the &lt;code&gt;_nghost-ng-&amp;lt;id&amp;gt;&lt;/code&gt; attribute is no longer present on the &lt;code&gt;my-app&lt;/code&gt; component, nor on any child elements. Styles added to &lt;code&gt;h1&lt;/code&gt; will now “leak” from the component and affect any other &lt;code&gt;h1&lt;/code&gt;s on the page. Had there been another &lt;code&gt;h1&lt;/code&gt; on the page, even in a completely different component, the &lt;code&gt;color: tomato&lt;/code&gt; style would be applied to it.&lt;/p&gt;

&lt;p&gt;There are valid reasons for turning encapsulation off, e.g. styling 3rd party components, or because parts of a component are dynamically created/moved to some other part of the DOM, e.g. a modal that is created as a child to &lt;code&gt;body&lt;/code&gt;. Whatever the case, beware that the styles you add to a component might have an effect on unrelated elements!&lt;/p&gt;

&lt;p&gt;But what if you want to disable view encapsulation on a component but still keep some, or all of its styles scoped to the component?&lt;/p&gt;

&lt;p&gt;You can achieve this by nesting the styles under the component’s selector, i.e.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;my-component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;tomato&lt;/span&gt;&lt;span class="p"&gt;;&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;&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%2Fc0pgmmlsxlmrhuaangy8.jpg" 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%2Fc0pgmmlsxlmrhuaangy8.jpg" alt="ViewEncapsulation.None with component selector" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ViewEncapsulation.ShadowDom&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Component.encapsulation&lt;/code&gt; can take a third value - &lt;a href="https://angular.io/api/core/ViewEncapsulation#ShadowDom" rel="noopener noreferrer"&gt;&lt;code&gt;ViewEncapsulation.ShadowDom&lt;/code&gt;&lt;/a&gt; but so far I’ve never used it in my apps. Once set, it &lt;em&gt;uses the browser’s native Shadow DOM API to encapsulate CSS styles, ...&lt;/em&gt; (taken from Angular’s docs).&lt;/p&gt;

&lt;p&gt;It looks like this in DevTools:&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%2F92nm1y3cdq7nrqgewj52.jpg" 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%2F92nm1y3cdq7nrqgewj52.jpg" alt="ViewEncapsulation.ShadowDom" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don’t have experience with &lt;code&gt;ShadowDom&lt;/code&gt;, so I’ve included it only for reference. You can decide for yourself whether it makes sense to use it in your apps.&lt;/p&gt;

&lt;p&gt;Well, that’s it! I hope you learned something new about style encapsulation in Angular.&lt;/p&gt;

&lt;p&gt;See you in the next post 👋&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@sadswim?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;ian dooley&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/DuBNA1QMpPA?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Overview over Angular’s repositories</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Wed, 16 Nov 2022 18:52:41 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/overview-over-angulars-repositories-5la</link>
      <guid>https://forem.com/playfulprogramming-angular/overview-over-angulars-repositories-5la</guid>
      <description>&lt;p&gt;I’ve been working with Angular for around 6 years now. It’s a great framework that I enjoy working with. It’s also quite a broad framework that includes a lot of things. The ecosystem around it is pretty big as well.&lt;/p&gt;

&lt;p&gt;A lot of times while working on a task, I go to Angular’s main repo and look at the source code to get a sense of how a particular feature works. I do that for Angular Material too. It’s quite exciting being able to do that. This gives one a feeling of mastery over one’s tools.&lt;/p&gt;

&lt;p&gt;I wondered how many [official] Angular repos and packages are there?&lt;/p&gt;

&lt;p&gt;In this post I’d like to create some kind of an overview over the many Angular repos and what they contain. The aim is to get an overview, of course, but also to see how far Angular stretches, and appreciate the work done by the Angular’s team and all of the amazing contributors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main Angular repo (&lt;a href="https://github.com/angular/angular" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Contains the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/animations" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/animations&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/bazel" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/bazel&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/benchpress" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/benchpress&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/common" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/common&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/compiler-cli" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/compiler-cli&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/core" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/core&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/elements" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/elements&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/forms" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/forms&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/language-service" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/language-service&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/localize" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/localize&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/misc/angular-in-memory-web-api" rel="noopener noreferrer"&gt;&lt;code&gt;angular-in-memory-web-api&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/platform-browser-dynamic" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/platform-browser-dynamic&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/platform-browser" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/platform-browser&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/platform-server" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/platform-server&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/router" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/router&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/service-worker" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/service-worker&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/upgrade" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/upgrade&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular/tree/main/packages/zone.js" rel="noopener noreferrer"&gt;&lt;code&gt;zone.js&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular/tree/main/aio" rel="noopener noreferrer"&gt;aio&lt;/a&gt; - documentation for the &lt;a href="https://angular.io" rel="noopener noreferrer"&gt;https://angular.io&lt;/a&gt; website&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular/tree/main/packages/examples" rel="noopener noreferrer"&gt;examples&lt;/a&gt; - small examples used in the API docs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular/tree/main/devtools" rel="noopener noreferrer"&gt;devtools&lt;/a&gt; - Angular DevTools browser extension&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular/tree/main/integration" rel="noopener noreferrer"&gt;integration&lt;/a&gt; - end-to-end and integration tests that mimic how Angular works&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Angular Components repo (&lt;a href="https://github.com/angular/components" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Contains the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/cdk-experimental" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/cdk-experimental&lt;/code&gt;&lt;/a&gt; - experimental components for Angular CDK&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/cdk" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/cdk&lt;/code&gt;&lt;/a&gt; - main Angular CDK package&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/google-maps" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/google-maps&lt;/code&gt;&lt;/a&gt; - Angular Google Maps component&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/material-date-fns-adapter" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/material-date-fns-adapter&lt;/code&gt;&lt;/a&gt; - Angular Material date-fns Adapter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/material-experimental" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/material-experimental&lt;/code&gt;&lt;/a&gt; - Experimental components for Angular Material&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/material-luxon-adapter" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/material-luxon-adapter&lt;/code&gt;&lt;/a&gt; - Angular Material Luxon Adapter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/material-moment-adapter" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/material-moment-adapter&lt;/code&gt;&lt;/a&gt; - Angular Material Moment Adapter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/material" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/material&lt;/code&gt;&lt;/a&gt; - main Angular Material package&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/src/youtube-player" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/youtube-player&lt;/code&gt;&lt;/a&gt; - Angular YouTube Player component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/components/tree/main/guides" rel="noopener noreferrer"&gt;guides&lt;/a&gt; - guides found in &lt;a href="https://material.angular.io/guides" rel="noopener noreferrer"&gt;Guides page&lt;/a&gt; on &lt;a href="https://material.angular.io" rel="noopener noreferrer"&gt;Angular Material&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Angular Components website repo (&lt;a href="https://github.com/angular/material.angular.io" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;The Angular app for the &lt;a href="https://material.angular.io" rel="noopener noreferrer"&gt;https://material.angular.io&lt;/a&gt; website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular Components Docs repo (&lt;a href="https://github.com/angular/material2-docs-content" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Auto-generated docs content used in the &lt;a href="https://material.angular.io" rel="noopener noreferrer"&gt;https://material.angular.io&lt;/a&gt; website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular CLI repo (&lt;a href="https://github.com/angular/angular-cli" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Contains the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular/cli" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/cli&lt;/code&gt;&lt;/a&gt; - main Angular CLI package&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular/create" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/create&lt;/code&gt;&lt;/a&gt; - create an Angular CLI workspace&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular/pwa" rel="noopener noreferrer"&gt;&lt;code&gt;@angular/pwa&lt;/code&gt;&lt;/a&gt; - a schematic for adding Progress Web App (PWA) support to an Angular app&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/architect" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/architect&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/architect_cli" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/architect-cli&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/benchmark" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/benchmark&lt;/code&gt;&lt;/a&gt; - Angular Devkit Benchmark. &lt;strong&gt;Note: Not stable&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/build_angular" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/build-angular&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/build_webpack" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/build-webpack&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/core" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/core&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/schematics" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/schematics&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/schematics_cli" rel="noopener noreferrer"&gt;&lt;code&gt;@angular-devkit/schematics-cli&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/ngtools/webpack" rel="noopener noreferrer"&gt;&lt;code&gt;@ngtools/webpack&lt;/code&gt;&lt;/a&gt; - Angular Compiler Webpack Plugin&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/angular/angular-cli/tree/main/packages/schematics/angular" rel="noopener noreferrer"&gt;&lt;code&gt;@schematics/angular&lt;/code&gt;&lt;/a&gt; - Schematics specific to Angular&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Angular Universal repo (&lt;a href="https://github.com/angular/universal" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Contains the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/universal/tree/main/modules/builders" rel="noopener noreferrer"&gt;&lt;code&gt;@nguniversal/builders&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/universal/tree/main/modules/common" rel="noopener noreferrer"&gt;&lt;code&gt;@nguniversal/common&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/angular/universal/tree/main/modules/express-engine" rel="noopener noreferrer"&gt;&lt;code&gt;@nguniversal/express-engine&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Angular Language Service repo (&lt;a href="https://github.com/angular/vscode-ng-language-service" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Angular extension for Visual Studio Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  ng-packagr repo (&lt;a href="https://github.com/ng-packagr/ng-packagr" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Compile and package Angular libraries in Angular Package Format (APF).&lt;/p&gt;

&lt;h3&gt;
  
  
  AngularFire repo (&lt;a href="https://github.com/angular/angularfire" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;The official Angular library for Firebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular Upgrade Guide (update.angular.io) repo (&lt;a href="https://github.com/angular/angular-update-guide" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;An interactive guide to updating the version of Angular in your apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  NGCC Validation repo (&lt;a href="https://github.com/angular/ngcc-validation" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Angular Ivy library compatibility validation project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular Contributor Code of Conduct repo (&lt;a href="https://github.com/angular/code-of-conduct" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;A code of conduct for all Angular projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular Flex-Layout repo (&lt;a href="https://github.com/angular/flex-layout" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note: Deprecated. Under LTS support.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Protractor repo (&lt;a href="https://github.com/angular/protractor" rel="noopener noreferrer"&gt;link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note: Deprecated. End of development as of Angular v15.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;What a list 😮 The Angular team is doing an awesome job maintaining these repos, working on new features, fixing bugs and moving Angular forward.&lt;/p&gt;




&lt;p&gt;Thanks to &lt;a href="https://twitter.com/LayZeeDK" rel="noopener noreferrer"&gt;Lars Gyrup Brink Nielsen&lt;/a&gt; for reviewing this post.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>github</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Resources to get started with Nx</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Thu, 10 Nov 2022 17:12:16 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/resources-to-get-started-with-nx-72p</link>
      <guid>https://forem.com/playfulprogramming/resources-to-get-started-with-nx-72p</guid>
      <description>&lt;p&gt;You know the old saying &lt;em&gt;“Ask me once, I’ll share a tweet. Ask me twice, I’ll share a tweet. Ask me a third time, I’ll share a blog post”&lt;/em&gt;? (ok, it’s not an old saying — &lt;a href="https://twitter.com/dzhavatushev/status/1590074512590401536" rel="noopener noreferrer"&gt;I came up with it two days ago&lt;/a&gt; 😅). Anyway, I was asked a couple of times on Twitter about getting started with Nx, so I thought I’d write a post collecting all sorts of links, resources, courses, people to follow, etc. that I can share next time someone asks 😎&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I’ll try to update the post as I discover new stuff, so send them my way if something’s not in the list bellow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Official Nx website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Blogs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.nrwl.io/" rel="noopener noreferrer"&gt;Official Nx Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/nx"&gt;Nx organization on DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/t/nx"&gt;Nx tag on DEV Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.nrwl.io/nx-newsletter" rel="noopener noreferrer"&gt;Nx Newsletter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub repos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl" rel="noopener noreferrer"&gt;Nrwl organization on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/nx" rel="noopener noreferrer"&gt;Main Nx repo on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/nx-examples" rel="noopener noreferrer"&gt;Example repo for Nx workspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/nx-recipes" rel="noopener noreferrer"&gt;Nx Recipes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Nx Console
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/nx-console" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console" rel="noopener noreferrer"&gt;Visual Studio Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Nx Cloud
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.app/" rel="noopener noreferrer"&gt;Nx Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/ci" rel="noopener noreferrer"&gt;Nx Cloud Github Workflows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.dev/community#plugin-directory" rel="noopener noreferrer"&gt;Nx Plugin Directory&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Video
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/nrwl_io" rel="noopener noreferrer"&gt;Nx YouTube Channel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Courses
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Free
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nxplaybook.com/p/nx-workspaces" rel="noopener noreferrer"&gt;Nx Workspaces (by Nrwl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://egghead.io/q/nx?access_state=free" rel="noopener noreferrer"&gt;Nx courses on Egghead&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Paid
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nxplaybook.com/p/advanced-nx-workspaces" rel="noopener noreferrer"&gt;Advanced Nx Workspaces (by Nrwl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://egghead.io/q/nx?access_state=pro" rel="noopener noreferrer"&gt;Nx courses on Egghead&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Books
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leanpub.com/the-angular-developers-nx-handbook" rel="noopener noreferrer"&gt;The Angular Developer's Nx Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.nrwl.io/angular-enterprise-monorepo-patterns-new-book" rel="noopener noreferrer"&gt;Enterprise Monorepo Angular Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.nrwl.io/react-book" rel="noopener noreferrer"&gt;Effective React Development with Nx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Community
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nx.dev/conf" rel="noopener noreferrer"&gt;Nx Conf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/NxDevTools" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go.nrwl.io/join-slack" rel="noopener noreferrer"&gt;Community Slack Channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twitch.tv/nxdevtools" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  People to follow
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nrwl.io/about-us" rel="noopener noreferrer"&gt;Everyone on Nrwl’s About Us page&lt;/a&gt; 🌟&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/i/lists/1171086812095205376" rel="noopener noreferrer"&gt;Nrwlians - Past and present Nrwl people (Twitter list)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Community members
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/dominik_pieper" rel="noopener noreferrer"&gt;Dominik Pieper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/gioragutt" rel="noopener noreferrer"&gt;Giora Guttsait&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/JordanHall_dev" rel="noopener noreferrer"&gt;Jordan Hall&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/JayCooperBell" rel="noopener noreferrer"&gt;Jay Bell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/LaraNerdsom" rel="noopener noreferrer"&gt;Lara Newsom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/LayZeeDK" rel="noopener noreferrer"&gt;Lars Gyrup Brink Nielsen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/puppo92" rel="noopener noreferrer"&gt;Luca Del Puppo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/ManfredSteyer" rel="noopener noreferrer"&gt;Manfred Steyer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/SantoshYadavDev" rel="noopener noreferrer"&gt;Santosh Yadav&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nx</category>
      <category>resources</category>
    </item>
    <item>
      <title>Fully expand PR status checks on GitHub</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Tue, 01 Nov 2022 21:56:23 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/fully-expand-pr-status-checks-on-github-4mml</link>
      <guid>https://forem.com/playfulprogramming/fully-expand-pr-status-checks-on-github-4mml</guid>
      <description>&lt;p&gt;One thing I absolutely love about working on the Web is that I can literally tweak any web page according to my preferences.&lt;/p&gt;

&lt;p&gt;You know, I can build a browser extension that changes colors, font sizes, improves accessibility, moves boxes, removes things I don’t need, etc. I can also write my own &lt;a href="https://www.freecodecamp.org/news/what-are-bookmarklets/" rel="noopener noreferrer"&gt;bookmarklet&lt;/a&gt; for doing the same.&lt;/p&gt;

&lt;p&gt;This is what I did recently after patiently enduring what I consider to be an annoying limitation on the PR (Pull Request) status checks list on GitHub.&lt;/p&gt;

&lt;p&gt;PR status checks is a list of checks that show the status of all pipeline runs related to a PR. They are usually the last section on the PR page right before the “merge” button and the comment section.&lt;/p&gt;

&lt;p&gt;What annoys me about this list is that it can’t be fully expanded. There’s a toggle to either hide all checks or show them but the list has a set height that limits how many items can be shown at a time. And sometimes the list can be quite long. If a run fails, it becomes quite annoying to scroll up and down to find what has failed.&lt;/p&gt;

&lt;p&gt;So I built my own bookmarklet that simply removes the height and thus the list expands fully. Needless to say, I use it all time now 😎&lt;/p&gt;

&lt;p&gt;Here’s a video 👇&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%2F7gplqxfqdhpl4eruyx48.gif" 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%2F7gplqxfqdhpl4eruyx48.gif" alt=" " width="480" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you want to use it too, here’s the source code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;javascript&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.merge-status-list.js-updatable-content-preserve-scroll-position&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy coding 😉&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Remember to enjoy it</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Tue, 25 Oct 2022 20:07:56 +0000</pubDate>
      <link>https://forem.com/dzhavat/remember-to-enjoy-it-5ff3</link>
      <guid>https://forem.com/dzhavat/remember-to-enjoy-it-5ff3</guid>
      <description>&lt;p&gt;It’s always been important to me to enjoy whatever I’m doing. Whether it’s work, a side project, writing on this blog, recording videos, going for a run or learning new stuff, simply enjoying it is the single most important factor that keeps me motivated.&lt;/p&gt;

&lt;p&gt;I don’t recall exactly when but a few months ago an idea popped up in my head - I wanted to decorate the wall above my desk with the quote “Remember to enjoy it” as a little reminder that I must enjoy whatever I’m doing. And to make it extra special, I wanted to cut each letter out of wood.&lt;/p&gt;

&lt;p&gt;So I got to work making small progress over time but enjoying it nonetheless (see 😉).&lt;/p&gt;

&lt;p&gt;I found a nice font on the Internet and printed each letter in the desired size. I transferred the letters on a piece of wood and used a jigsaw to cut them. Then I used small wood files to smoothen the edges. Finally I applied a couple of coats of dark stain to make the letters darker.&lt;/p&gt;

&lt;p&gt;And finally today I put the letters on the wall using double-sided tape. It’s beautiful. I like it a lot 🙂&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%2F9cwqdlm1m7y4mxtvi0z1.jpg" 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%2F9cwqdlm1m7y4mxtvi0z1.jpg" alt="“Remember to enjoy it” wooden letters" width="800" height="1216"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>personal</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Auto-expand menu using Angular Material</title>
      <dc:creator>Dzhavat Ushev</dc:creator>
      <pubDate>Wed, 14 Sep 2022 14:31:25 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/auto-expand-menu-using-angular-material-34p0</link>
      <guid>https://forem.com/playfulprogramming-angular/auto-expand-menu-using-angular-material-34p0</guid>
      <description>&lt;p&gt;This post is going to be a bit longer than usual so bear with me 🙂&lt;/p&gt;

&lt;p&gt;I was working on a task at work where one of the requirements was to make a menu auto-expand whenever the user navigates to a sub-page that is part of a menu group. To give you a visual idea, take a look at the following video:&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%2Fz5sa5s3pwa3sjtdstzxf.gif" 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%2Fz5sa5s3pwa3sjtdstzxf.gif" alt="Final demo" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pages 3 and 4 are grouped under "Nested menu" and the menu auto-expands when the user navigates to one of those pages.&lt;/p&gt;

&lt;p&gt;Looks nice, doesn't it? 😎&lt;/p&gt;

&lt;p&gt;In this post I'll show you how I built it. It's not hard to achive but there's one disclaimer.&lt;/p&gt;

&lt;p&gt;The disclaimer: The solution I'm going to share in this post is specific to our components architecture. If you want to achieve the same in your project, the final solution might be different. So let me tell you a bit more about our setup before diving into the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components architecture
&lt;/h3&gt;

&lt;p&gt;The application I'm working on is made up of two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application specific components&lt;/li&gt;
&lt;li&gt;Design System components&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Design System components
&lt;/h4&gt;

&lt;p&gt;As you might've guessed it, the Design System consists of small components focused on particular UI needs. They are used in the application.&lt;/p&gt;

&lt;p&gt;As part of the Design System, we've got components like &lt;code&gt;nav-list&lt;/code&gt; and &lt;code&gt;nav-list-item&lt;/code&gt;, and an &lt;code&gt;expand-on-active-link&lt;/code&gt; directive where the real magic happens 🪄&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;code&gt;nav-list-item&lt;/code&gt; component
&lt;/h5&gt;

&lt;p&gt;This component is a wrapper around &lt;code&gt;mat-list-item&lt;/code&gt; from Material and has two requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Should support internal links&lt;/li&gt;
&lt;li&gt;Should support external links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The component class has a &lt;code&gt;link&lt;/code&gt; Input and some logic that decides whether the link is internal or external. That's not important for this post but you can see it in the final GitHub repo.&lt;/p&gt;

&lt;p&gt;Here's its template at this point:&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="c"&gt;&amp;lt;!-- nav-list-item.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;
  &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isExternalLink; else internalLink"&lt;/span&gt;
  &lt;span class="na"&gt;mat-list-item&lt;/span&gt;
  &lt;span class="na"&gt;mat-ripple&lt;/span&gt;
  &lt;span class="na"&gt;[href]=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;
  &lt;span class="na"&gt;[attr.target]=&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"templateContent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#internalLink&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;mat-list-item&lt;/span&gt; &lt;span class="na"&gt;mat-ripple&lt;/span&gt; &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt; &lt;span class="na"&gt;routerLinkActive=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"templateContent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#templateContent&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  &lt;code&gt;nav-list&lt;/code&gt; component
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;nav-list&lt;/code&gt; is a wrapper around &lt;code&gt;mat-nav-list&lt;/code&gt; from Material. The component has an &lt;code&gt;expandable&lt;/code&gt; Input property that, when set to &lt;code&gt;true&lt;/code&gt;, places a &lt;code&gt;mat-nav-list&lt;/code&gt; (and its projected content) inside a &lt;code&gt;mat-expansion-panel&lt;/code&gt;, otherwise it displays &lt;code&gt;mat-nav-list&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;Here's its template at this point:&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="c"&gt;&amp;lt;!-- mat-nav-list.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"expandable; else navListTemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mat-expansion-panel&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mat-elevation-z0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mat-expansion-panel-header&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;mat-panel-title&amp;gt;&lt;/span&gt;{% raw %}{{ title }}{% endraw %}&lt;span class="nt"&gt;&amp;lt;/mat-panel-title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mat-expansion-panel-header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"navListTemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mat-expansion-panel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#navListTemplate&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;mat-nav-list&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/mat-nav-list&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll come back to the &lt;code&gt;expand-on-active-link&lt;/code&gt; directive later.&lt;/p&gt;

&lt;h4&gt;
  
  
  Application specific components
&lt;/h4&gt;

&lt;p&gt;The application specific components is where components from the Design System are used.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;sidebar-nav&lt;/code&gt; component
&lt;/h3&gt;

&lt;p&gt;The component simply puts &lt;code&gt;nav-list&lt;/code&gt; and &lt;code&gt;nav-list-item&lt;/code&gt; together. Its template is as follows:&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="c"&gt;&amp;lt;!-- sidebar-nav.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;nav-list&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav-list-item&lt;/span&gt; &lt;span class="na"&gt;link=&lt;/span&gt;&lt;span class="s"&gt;"/page-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 1&lt;span class="nt"&gt;&amp;lt;/nav-list-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav-list-item&lt;/span&gt; &lt;span class="na"&gt;link=&lt;/span&gt;&lt;span class="s"&gt;"/page-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 2&lt;span class="nt"&gt;&amp;lt;/nav-list-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav-list-item&lt;/span&gt; &lt;span class="na"&gt;link=&lt;/span&gt;&lt;span class="s"&gt;"https://angular.io/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Angular&lt;span class="nt"&gt;&amp;lt;/nav-list-item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav-list&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;nav-list&lt;/span&gt; &lt;span class="na"&gt;[expandable]=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;[title]=&lt;/span&gt;&lt;span class="s"&gt;"'Nested menu'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav-list-item&lt;/span&gt; &lt;span class="na"&gt;link=&lt;/span&gt;&lt;span class="s"&gt;"/page-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 3&lt;span class="nt"&gt;&amp;lt;/nav-list-item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav-list-item&lt;/span&gt; &lt;span class="na"&gt;link=&lt;/span&gt;&lt;span class="s"&gt;"/page-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Page 4&lt;span class="nt"&gt;&amp;lt;/nav-list-item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav-list&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the code above, the first &lt;code&gt;nav-list&lt;/code&gt; displays a list of links while the second &lt;code&gt;nav-list&lt;/code&gt; displays an expandable list of links grouped under the "Nested menu" title. Demo time ⌚&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%2Fys46lp8ytsh6r9q4xuc6.gif" 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%2Fys46lp8ytsh6r9q4xuc6.gif" alt="Menu that must be expanded manually" width="930" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The expandable menu must be opened manually. Any highlighted menu item is hidden until the menu is expanded which can be confusing for the user. We want to fix that by adding auto-expand capabilities. Let's see how.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making the menu auto-expand
&lt;/h3&gt;

&lt;p&gt;First let's define some requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An expandable menu should automatically expand when the user navigates to a sub-page that is part the menu.&lt;/li&gt;
&lt;li&gt;An already expanded menu should stay open when the user navigates to another top level page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are probably a few solutions here. One could be to listen for the &lt;a href="https://angular.io/api/router/NavigationEnd" rel="noopener noreferrer"&gt;&lt;code&gt;NavigationEnd&lt;/code&gt;&lt;/a&gt; router event and somehow figure out which &lt;code&gt;nav-list&lt;/code&gt; to expand based on routes. Another could be to listen for the &lt;a href="(https://angular.io/api/router/RouterLinkActive#properties)"&gt;&lt;code&gt;isActiveChange&lt;/code&gt;&lt;/a&gt; event on each &lt;a href="https://angular.io/api/router/RouterLink" rel="noopener noreferrer"&gt;&lt;code&gt;routerLink&lt;/code&gt;&lt;/a&gt; and expand the closest &lt;code&gt;nav-list&lt;/code&gt;. This is the approach I used.&lt;/p&gt;

&lt;p&gt;So there are a few changes that needs to be made.&lt;/p&gt;

&lt;h4&gt;
  
  
  Modifying the &lt;code&gt;nav-list-item&lt;/code&gt; component
&lt;/h4&gt;

&lt;p&gt;Remember how this component supports internal and external links? Well, each internal link uses the &lt;code&gt;routerLink&lt;/code&gt; directive, which conveniently has an &lt;code&gt;isActiveChange&lt;/code&gt; Output property that emits &lt;code&gt;true&lt;/code&gt; every time a link becomes active and &lt;code&gt;false&lt;/code&gt; when it becomes inactive. For now we’ll simply forward the emitted value to another Output property on the &lt;code&gt;nav-list&lt;/code&gt; component class. We’ll see why later.&lt;/p&gt;

&lt;p&gt;So the component class and its template now look like this:&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="c"&gt;&amp;lt;!-- nav-list-item.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt; &lt;span class="na"&gt;(isActiveChange)=&lt;/span&gt;&lt;span class="s"&gt;"isActive.emit($event)"&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// nav-list-item.component.ts&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="c1"&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;nav-list-item&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NavListItemComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;h4&gt;
  
  
  Modifying the &lt;code&gt;nav-list&lt;/code&gt; component
&lt;/h4&gt;

&lt;p&gt;What we want to do here is query the template for all the projected &lt;code&gt;nav-list-item&lt;/code&gt; components. We can use the &lt;code&gt;@ContentChildren&lt;/code&gt; decorator for that.&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="c1"&gt;// nav-list.component.ts&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="c1"&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;nav-list&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NavListComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContentChildren&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NavListItemComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;navListItemComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavListItemComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;Once we have all &lt;code&gt;nav-list-item&lt;/code&gt; components we're going to send them to a custom directive (shown below) that will listen for the &lt;code&gt;isActive&lt;/code&gt; event on each link within a sub-menu and expand the related &lt;code&gt;mat-expansion-panel&lt;/code&gt; component in case any of the links emit &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's modify the &lt;code&gt;nav-list&lt;/code&gt; template first, then we'll look at the custom directive.&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="c"&gt;&amp;lt;!-- nav-list.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;mat-expansion-panel&lt;/span&gt;
  &lt;span class="na"&gt;expandOnActiveLink&lt;/span&gt;
  &lt;span class="na"&gt;[navListItemComponents]=&lt;/span&gt;&lt;span class="s"&gt;"navListItemComponents"&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mat-expansion-panel&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, a custom &lt;code&gt;expandOnActiveLink&lt;/code&gt; directive is added only on the &lt;code&gt;mat-expansion-panel&lt;/code&gt;. The directive has one Input called &lt;code&gt;navListItemComponents&lt;/code&gt; which takes a list of &lt;code&gt;nav-list-item&lt;/code&gt; components.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;expand-on-active-link&lt;/code&gt; directive
&lt;/h4&gt;

&lt;p&gt;Here's the power of Angular's directives. When you add a directive to a component, you can inject an instance of that component in the directive's &lt;code&gt;constructor&lt;/code&gt;. We're going to use that for our advantage.&lt;/p&gt;

&lt;p&gt;The plan is to inject an instance of &lt;a href="https://material.angular.io/components/expansion/api#MatExpansionPanel" rel="noopener noreferrer"&gt;&lt;code&gt;MatExpansionPanel&lt;/code&gt;&lt;/a&gt; in the directive and use its &lt;code&gt;open&lt;/code&gt; method to expand the panel whenever one of the projected &lt;code&gt;nav-list-item&lt;/code&gt; components emits &lt;code&gt;true&lt;/code&gt; from its &lt;code&gt;isActive&lt;/code&gt; Output.&lt;/p&gt;

&lt;p&gt;Let's first see the directive, then we'll talk about the code:&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="c1"&gt;// expand-on-active-link.directive.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&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;[expandOnActiveLink]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exportAs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expandOnActiveLink&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="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;ExpandOnActiveLinkDirective&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterContentInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;navListItemComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavListItemComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MatExpansionPanel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngAfterContentInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navListItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navListItemComponents&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navListItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navListItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Looks like there's a bug in `mat-drawer` component&lt;/span&gt;
          &lt;span class="c1"&gt;// that prevents `mat-expansion-panel` from expanding&lt;/span&gt;
          &lt;span class="c1"&gt;// This littl' fella fixes it :)&lt;/span&gt;
          &lt;span class="nf"&gt;setTimeout&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="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&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;A few things to note here. First, &lt;code&gt;navListItemComponents&lt;/code&gt; are accessed in the &lt;a href="https://angular.io/api/core/AfterContentInit" rel="noopener noreferrer"&gt;&lt;code&gt;ngAfterContentInit&lt;/code&gt;&lt;/a&gt; lifecycle hook because &lt;a href="https://angular.io/api/core/ContentChildren" rel="noopener noreferrer"&gt;&lt;code&gt;ContentChildren&lt;/code&gt;&lt;/a&gt; queries are set right before it. Second, the &lt;a href="https://rxjs.dev/api/index/function/from" rel="noopener noreferrer"&gt;&lt;code&gt;from&lt;/code&gt;&lt;/a&gt; function takes an array of &lt;code&gt;nav-list-item&lt;/code&gt; components and sends each component to the &lt;a href="https://rxjs.dev/api/index/function/mergeMap" rel="noopener noreferrer"&gt;&lt;code&gt;mergeMap&lt;/code&gt;&lt;/a&gt; operator. &lt;code&gt;mergeMap&lt;/code&gt; picks up the &lt;code&gt;isActive&lt;/code&gt; Output property of each component and merges their events into a single stream. The &lt;code&gt;filter&lt;/code&gt; operator afterwards makes sure that only &lt;code&gt;true&lt;/code&gt; events will continue down the stream. At the end, the injected &lt;code&gt;panel&lt;/code&gt; instance is used to open the &lt;code&gt;MatExpansionPanel&lt;/code&gt; component. &lt;code&gt;setTimeout&lt;/code&gt; is used because at the time of this writing, apparently there's a bug in Material that prevents &lt;code&gt;mat-expansion-panel&lt;/code&gt; from expanding if it is placed inside a &lt;code&gt;mat-drawer&lt;/code&gt; 🤷‍♂️.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final demo
&lt;/h3&gt;

&lt;p&gt;Wow, that was a lot! Here's a final &lt;a href="https://stackblitz.com/github/dzhavat/angular-material-auto-expand-sidebar-menu?file=src/app/sidebar-nav.component.ts" rel="noopener noreferrer"&gt;StackBlitz demo&lt;/a&gt;. Also a &lt;a href="https://github.com/dzhavat/angular-material-auto-expand-sidebar-menu" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope you liked this post. It's very specific to a particular component setup but an interesting challenge nonetheless.&lt;/p&gt;

&lt;p&gt;Oh, but we're not done yet! This is the part where &lt;strong&gt;you&lt;/strong&gt; come in. Do you have a suggestion for improving the solution? What can be done differently? Let me know on &lt;a href="https://twitter.com/dzhavatushev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>material</category>
    </item>
  </channel>
</rss>
