<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Preston Lamb</title>
    <description>The latest articles on DEV Community by Preston Lamb (@prestonjlamb).</description>
    <link>https://dev.to/prestonjlamb</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%2F158451%2F3bbe5b9c-77f3-446b-b6b0-1d59c8696cc4.png</url>
      <title>DEV Community: Preston Lamb</title>
      <link>https://dev.to/prestonjlamb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prestonjlamb"/>
    <language>en</language>
    <item>
      <title>Git Worktrees In Use</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Fri, 09 Dec 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/git-worktrees-in-use-ho1</link>
      <guid>https://dev.to/prestonjlamb/git-worktrees-in-use-ho1</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Most of us use Git every day, but generally use only the features that we are familiar with and allow us to do our job. There's nothing wrong with this at all, but learning new tricks can take your productivity up a level! With that in mind, let me introduce you to Git Worktrees.&lt;/p&gt;

&lt;p&gt;Git Worktrees allow you to pull a git repository to your computer and then work on multiple branches at a time if desired. A standard &lt;code&gt;git clone&lt;/code&gt; command pulls the repository to your machine and starts you working on a particular branch. If you need to switch branches, you have to either commit and push your code or stash the changes. When you clone the repo with the intent to use worktrees, you don't check out a particular branch initially. Let's learn how to use Git Worktrees!&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloning Your Repo
&lt;/h2&gt;

&lt;p&gt;Let's start by cloning the repository to your machine.&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="nv"&gt;$ &lt;/span&gt;git clone &lt;span class="nt"&gt;--bare&lt;/span&gt; git@github.com:pjlamb12/worktree-demo.git worktree-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command looks similar to your normal &lt;code&gt;git clone&lt;/code&gt;, with one important extra piece: &lt;code&gt;--bare&lt;/code&gt;. This flag is what clones the repo to your machine without checking out a particular branch. You can read more about the flag &lt;a href="https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---bare"&gt;here&lt;/a&gt;. The last part of the command, &lt;code&gt;worktree-demo&lt;/code&gt;, names the folder that the repository will be cloned into. Normally &lt;code&gt;git clone&lt;/code&gt; will clone the repo into a folder that's named the same as the repository URL, minus the &lt;code&gt;.git&lt;/code&gt;. &lt;code&gt;git clone --bare&lt;/code&gt; will keep the &lt;code&gt;.git&lt;/code&gt; extension on the folder when cloning. If you don't want the &lt;code&gt;.git&lt;/code&gt; on the folder name, provide the name of the folder as I've done above.&lt;/p&gt;

&lt;p&gt;At this point, you have the repository cloned to your machine. If you change into the directory and list the contents, you'll see a few files like &lt;code&gt;HEAD&lt;/code&gt;, &lt;code&gt;config&lt;/code&gt;, and &lt;code&gt;description&lt;/code&gt;, along with a couple folders like &lt;code&gt;hooks&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, and &lt;code&gt;objects&lt;/code&gt;. This is just an example; yours may not be exactly the same.&lt;/p&gt;

&lt;p&gt;If you run the &lt;code&gt;git status&lt;/code&gt; command, you'll see an error that says something along the lines of, "this operation must be run in a work tree". This lets you know that you can't do any work on your repository in this main folder. Let's look next at how to create a worktree so you can make some changes to your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Worktree
&lt;/h2&gt;

&lt;p&gt;Let's add our first worktree, which we'll call &lt;code&gt;main&lt;/code&gt; and will be based off the &lt;code&gt;HEAD&lt;/code&gt; of the repo. You can add that worktree like this:&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="nv"&gt;$ &lt;/span&gt;git worktree add main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you list the contents of the directory, you'll now see a new folder called &lt;code&gt;main&lt;/code&gt;. If you change into that directory and list the contents you'll see your application code. Also, &lt;code&gt;git status&lt;/code&gt; will now give you the status that you expect to see. You'll no longer see the error mentioned above.&lt;/p&gt;

&lt;p&gt;You can now always view the code in your repository at the &lt;code&gt;main&lt;/code&gt; branch. To update the worktree, run the &lt;code&gt;git pull&lt;/code&gt; command. This will get all the latest commits to the branch and update your worktree. I recommend not doing any work on your application in this worktree, however. This worktree is useful to have on your computer and ready to go so that you can troubleshoot any issues that teammates may be having, for example. If you want to make a change to the application, create a new worktree just like you would create a new branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a Worktree with a New Branch
&lt;/h3&gt;

&lt;p&gt;The command to create a new worktree and a new branch is similar to the &lt;code&gt;add&lt;/code&gt; command above, but with an extra flag.&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="nv"&gt;$ &lt;/span&gt;git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; my-new-branch worktree-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flag you need to provide is the &lt;code&gt;-b branch-name&lt;/code&gt; flag. Whatever you use as the value for this flag will be the name of the branch when you push it to the repository. The last argument, &lt;code&gt;worktree-name&lt;/code&gt;, is the name of the worktree on your computer and will be the name of the folder where the code is stored. This command does the same thing as the first &lt;code&gt;add&lt;/code&gt; command, but a new branch is created with the given name.&lt;/p&gt;

&lt;p&gt;Now that you have a worktree and branch created to make your changes, you can work on your application the same as you always do. Make changes, commit them, push them, and then merge the pull request. The first time you push the code, remember to use the &lt;code&gt;--set-upstream&lt;/code&gt; flag:&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="nv"&gt;$ &lt;/span&gt;git push &lt;span class="nt"&gt;--set-upstream&lt;/span&gt; origin my-new-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you've used this flag the first time, &lt;code&gt;git push&lt;/code&gt; will suffice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a Worktree Based on a Remote Branch
&lt;/h3&gt;

&lt;p&gt;The above commands are helpful but don't cover all situations. Sometimes you need to help your coworker with an issue they are seeing on their branch. This is where you can really see the benefits of worktrees. You can leave the worktree that you're working on untouched on your machine, and add a new worktree based on your coworker's branch. You can add this new worktree like this:&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="nv"&gt;$ &lt;/span&gt;git worktree add worktree-name branch-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, this is similar to the first &lt;code&gt;add&lt;/code&gt; command but the &lt;code&gt;branch-name&lt;/code&gt; argument will start you off on a branch in the repository instead of from the &lt;code&gt;HEAD&lt;/code&gt; commit. You'll be able to change into the worktree folder and browse the code as your coworker is seeing it, but you won't have been required to commit your unfinished code to switch branches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating a Worktree
&lt;/h2&gt;

&lt;p&gt;Often when you're working on a feature branch the main branch has someone else's code merged to it. At that point you'll need to update your feature branch with &lt;code&gt;rebase&lt;/code&gt; or &lt;code&gt;merge&lt;/code&gt;. These same methods of updating your worktree can be used. You can update your worktree by rebasing or merging. You can decide the which method you would like to use. &lt;a href="https://betterprogramming.pub/differences-between-git-merge-and-rebase-and-why-you-should-care-ae41d96237b6"&gt;This article&lt;/a&gt; explains the differences between &lt;code&gt;rebase&lt;/code&gt; and &lt;code&gt;merge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before merging or rebasing, make sure that your local &lt;code&gt;main&lt;/code&gt; worktree has been updated with &lt;code&gt;git pull&lt;/code&gt;. After your local worktree is updated, you can &lt;code&gt;merge&lt;/code&gt; or &lt;code&gt;rebase&lt;/code&gt; your feature branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing a Worktree
&lt;/h2&gt;

&lt;p&gt;After you finish up with a worktree, you'll want to remove the worktree from your machine. Each worktree will take up space on your hard drive, so you'll eventually run out room if you don't remove unused workspaces. You can remove them with the &lt;code&gt;remove&lt;/code&gt; command:&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="nv"&gt;$ &lt;/span&gt;git worktree remove worktree-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The worktree and all related files will be removed from your computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Listing Worktrees
&lt;/h2&gt;

&lt;p&gt;If you need to list the worktrees you've created, you can use the &lt;code&gt;list&lt;/code&gt; command:&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="nv"&gt;$ &lt;/span&gt;git worktree list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will list all the local worktrees you've created on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When I found out about worktrees, I could see the potential benefits immediately. The ability to have multiple branches checked out on your computer at a single time is really powerful, especially when working with a team. Gone are the days of committing completely unfinished code to your feature branch so you can switch branches to help a coworker. It's not necessarily a "one size fits all" solution, but I'm excited about the possibilities. Hopefully this article helps you get started&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Nx Conf 2022 Recap</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Wed, 09 Nov 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/nx-conf-2022-recap-55b</link>
      <guid>https://dev.to/prestonjlamb/nx-conf-2022-recap-55b</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Nx Conf 2022 is in the books, and it was great. The in person group was small, but not too small. It was a great size for being able to interact with fellow attendees, speakers, and Nrwl team members. The speakers were well prepared with practical examples of how to best use Nx to improve the maintainability and architecture of your applications. Here’s a brief overview of some of my favorite talks. But I mean it when I say that just because I don’t mention a talk doesn’t mean it wasn’t good; these are simply talks that will benefit me and the projects I work on in the next few weeks. The presentations will be released soon, and when they are you should go watch them!&lt;/p&gt;

&lt;h2&gt;
  
  
  Generators
&lt;/h2&gt;

&lt;p&gt;Many people talked about the importance of using generators, custom or community, to improve the quality of your application. Automating tasks that otherwise need to be done manually means you as a developer can be more efficient, but it also limits the number of times people can accidentally mess something up.&lt;/p&gt;

&lt;p&gt;My favorite talk on the subject was by Lara Newsom. She gave a very practical use case for why you would use custom generators, and walked through how to create one. In 25 minutes I went from being overwhelmed by creating a generator to being ready to build one on my own. (Coincidentally, this was one of Lara’s goals for her talk. She succeeded 😉).&lt;/p&gt;

&lt;p&gt;In Lara’s example, she showed how to compose other generators, in this case the Angular library creation generator, to limit the number of inputs available to only ones that your project actually cares about. This allows for consistency when creating the libraries, and prevents other developers from being overwhelmed about creating the libraries needed for your app. This is something that I plan on implementing for our workspace as soon as possible. I plan to do the same for creating apps and components so that everything is created with consistency and with the correct files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component Testing
&lt;/h2&gt;

&lt;p&gt;I think we can all agree that testing is not always the highest task on our list. But it is a vital part of having a stable application. Cypress has definitely changed the way I think about writing tests. The developer experience is so smooth, and it just feels good to write tests.&lt;/p&gt;

&lt;p&gt;The newest Cypress feature for Angular is component testing. The ability to isolate a component and test its actual display and interactivity is really appealing. The component is mounted and run in an actual browser, and can be tested to ensure it behaves and looks as it is supposed to. This is another tool in the testing tool belt, and one that I plan to spend some more time looking into.&lt;/p&gt;

&lt;p&gt;The Cypress and Nx teams have made it easy to get things set up in your app for component testing. This is yet another example of a great development experience: the migrations are essentially handled for you, and you just reap the benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI
&lt;/h2&gt;

&lt;p&gt;Multiple people also spoke about the benefit of using Nx Cloud, and the amount of time that is saved by running tests, builds, or linting while using Nx Cloud is mind-boggling. If you have things set up correctly on your CI, the amount of time your CI run takes to complete can be significantly faster than otherwise. The time is saved by caching the output of certain actions and replaying it if the affected code hasn’t changed. Thus you don’t need to continue to re-test or re-build your code. It was said that one client saves 40,000 hours a month in their CI time by using Nx Cloud. That’s likely on a fairly large app, but even smaller apps can save hours over the course of a month all of which is time back in your life and money back in your pocket.&lt;/p&gt;

&lt;p&gt;If you need to get started with getting your CI set up properly, Nx provides a generator to add different CI workflows for you. It’s straight forward and worth the time investment up front. (Quick story: I found a bug in the generated GitHub Action, and within a couple hours of creating an issue the issue was resolved. You can’t ask for a better response time than that.) After getting the CI file from the generator, you can be up and running pretty quickly and start reaping the benefits of Nx Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  General Conference Experience
&lt;/h2&gt;

&lt;p&gt;I’ve been to several rounds of ng-conf and it’s always a great time, but the size of it can make you feel lost and it’s pretty easy to blend in. That was not the case at Nx Conf this year. I don’t know the final numbers, but I’d guess there were about 100 people in person, maybe slightly more, but it was a great size. It was easier to find people to talk to, and to really make connections with people. I’ve interacted with many on the Nrwl team on Twitter over the last few years, but hadn’t met many of them in person. But because of the size of the conference it was so much easier to approach them and talk to the, both during the conference and at the after party.&lt;/p&gt;

&lt;p&gt;The Nrwl team, and ZeroSlope Events, did such a great job with everything about the conference. The hotel was great, the amenities were great, the location was great. I will definitely be shooting to make it back to the next Nx Conf&lt;/p&gt;

</description>
      <category>nx</category>
      <category>angular</category>
    </item>
    <item>
      <title>RxJS: defaultIfEmpty</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/rxjs-defaultifempty-572f</link>
      <guid>https://dev.to/prestonjlamb/rxjs-defaultifempty-572f</guid>
      <description>&lt;h1&gt;
  
  
  RxJS: defaultIfEmpty
&lt;/h1&gt;

&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;RxJS pipelines are convenient ways to get work done in your applications. You can essentially tell the app the steps it needs to take, and it will go step by step through the pipeline. But what if one of the steps will potentially be empty, but you want the pipeline to continue? That’s where the &lt;code&gt;defaultIfEmpty&lt;/code&gt; operator can come in handy. I recently learned about it when I had a similar situation, and it worked perfectly for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I was recently working on an application where you needed to be able to add, edit, and delete data. The work needed to be done in a certain order: deletions first, then additions or edits. This is straightforward as long as there are actions for each of the above types to be done: at least one add, one edit, and one delete. But what happens if one of those types doesn’t need to be done in a given pipeline?&lt;/p&gt;

&lt;p&gt;This is the situation I found myself in. If the delete observable was empty, nothing happened. I needed the pipeline to continue, however, and move on to adds and edits. I started searching around and found the &lt;code&gt;defaultIfEmpty&lt;/code&gt; operator, which solved my problem for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;defaultIfEmpty&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.learnrxjs.io/learn-rxjs/operators/conditional/defaultifempty"&gt;&lt;code&gt;defaultIfEmpty&lt;/code&gt;&lt;/a&gt; operator does exactly what it sounds like: it provides a default value in the pipeline if the preceding observable doesn’t emit a value. This ensures that the pipeline doesn’t get stuck, but instead outputs a value.&lt;/p&gt;

&lt;p&gt;Let’s look at a couple examples. First we’ll look at an example pipeline where there is a type for adds, edits, and deletes.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deletions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete 1&lt;/span&gt;&lt;span class="dl"&gt;'&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;additions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add 1&lt;/span&gt;&lt;span class="dl"&gt;'&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;edits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;

&lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;deletions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;additions&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;additionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;edits&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, this pipeline will execute as expected. The deletion observables will run and emit a value, then the additions, then the edits. The result of all three sections will be logged to the console. Easy enough, right? But what do we do if we have no deletions to run?&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deletions2&lt;/span&gt; &lt;span class="o"&gt;=&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;additions2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add 2&lt;/span&gt;&lt;span class="dl"&gt;'&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;edits2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;

&lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;deletions2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;additions2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;additionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;edits2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, nothing gets logged to the console. We never move past the first step, because nothing is ever emitted from the initial &lt;code&gt;zip(...deletions2)&lt;/code&gt; portion of the pipeline. But just because we don’t have anything to delete doesn’t mean we don’t want to continue with adding and editing the other pieces. This is where the &lt;code&gt;defaultIfEmpty&lt;/code&gt; operator comes in handy. Insert it after a given step in the observable pipeline that could potentially emit no data. Then the pipeline will continue. Continuing with the above example, we can change it to the following to get our pipeline working again.&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="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;deletions2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;defaultIfEmpty&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;additions2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;additionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;edits2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our pipeline continues and values are logged to the console. The &lt;code&gt;defaultIfEmpty([])&lt;/code&gt; operator essentially says if the preceding observable doesn’t emit a value, emit an empty array and then continue on to the next step. So, although we don’t have anything to delete, we can still do our adds and edits.&lt;/p&gt;

&lt;p&gt;Let’s look at one last example, where we have deletions and edits to do, but no additions. Can you guess what will happen?&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deletions3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete3&lt;/span&gt;&lt;span class="dl"&gt;'&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;additions3&lt;/span&gt; &lt;span class="o"&gt;=&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;edits3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit 3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;

&lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;deletions3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;additions3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;additionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;edits3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you guessed nothing happens at all, you’re close. But it does finish the delete step before stopping. So your edits never occur. To fix the issue, we just need to add another &lt;code&gt;defaultIfEmpty&lt;/code&gt; operator.&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="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;deletions3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;additions3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultIfEmpty&lt;/span&gt;&lt;span class="p"&gt;([]))),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;additionResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additionResult&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;switchMap&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;zip&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;edits3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editsResult&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: You can add the &lt;code&gt;defaultIfEmpty&lt;/code&gt; operator in the pipe for the additions like I have above, or you can add it directly after the &lt;code&gt;switchMap&lt;/code&gt;; either way will work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this minor change to our pipeline, it now finishes as we expect. The deletions are made, followed by the edits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I was initially stuck with figuring out how to make sure my pipeline continued, even if there was an empty step in the pipeline. But I should have known there was an operator to help me out. There are a lot of operators, and while it makes RxJS seem overwhelming at first it’s also very convenient for situations like this. When you get stuck, ask for help and read the docs. You’re likely to find someone who’s run into the same problem and can point you in the right direction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/edit/pjlamb12-rxjs-default-if-empty"&gt;Here’s a StackBlitz&lt;/a&gt; with the examples we looked at above&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Astro + Angular</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Thu, 15 Sep 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/astro-angular-3gfk</link>
      <guid>https://dev.to/prestonjlamb/astro-angular-3gfk</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Astro is a relatively new, all-in-one framework with the goal of creating performant, content-focused websites. The great part is that while there is some new Astro specific syntax you can learn, you can also bring your own frontend. Until recently, Angular was the exception to that rule. But with the release of standalone components to the Angular framework, you can now pair Astro and Angular together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;We won’t go fully into what Astro is in this blog post, but we’ll at least get into the basics. On June 8th, 2021, &lt;a href="https://astro.build/blog/introducing-astro/"&gt;a blog post was released by the Astro&lt;/a&gt; team explaining that their goal was to provide a web framework that shipped less JavaScript to the browser. It is described as similar to a static site generator, similar to Jekyll or Eleventy. After the build step, most JavaScript is removed from the page, and all that’s left is the HTML. In the case that JavaScript is needed for some functionality, Astro loads only the necessary JavaScript. The result are sites that are as lightweight and fast as possible. In the time since that blog post was released, a lot of content has been produced. If you’re interested in Astro, you should definitely go read more about it.&lt;/p&gt;

&lt;p&gt;To get started with Astro, you only need to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init astro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few prompts will be displayed; follow them through to the end and you should have your basic project ready to go. Once the project is completed, you’re ready to go on to the next steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Angular and Astro
&lt;/h2&gt;

&lt;p&gt;As mentioned in the intro, Astro allows you to bring your own frontend to build your site. React, Vue, and Svelte have been supported since the beginning. Angular was not available until v14.2, when standalone components were introduced. With that addition to the framework, you can now pair Angular and Astro.&lt;/p&gt;

&lt;p&gt;Another thing to be aware of, however, is that Angular’s standalone components don’t work 100% with Astro. For example, inputs to components work but outputs don’t. You’ll need to be aware of this when developing your application.&lt;/p&gt;

&lt;p&gt;Now that you have an Astro application, let’s get it working with Angular. You can do that with a single command from your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx astro add @analogjs/astro-angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command makes changes to the &lt;code&gt;astro.config.mjs&lt;/code&gt; file, and installs some Angular dependencies for you to develop your site. There’s one more step needed after this, and that is to create a &lt;code&gt;tsconfig.app.json&lt;/code&gt; file. You can find &lt;a href="https://github.com/analogjs/analog/blob/main/apps/astro-app/tsconfig.app.json"&gt;an example here&lt;/a&gt;. Add that file into the root of your project.&lt;/p&gt;

&lt;p&gt;Let’s continue by creating a component in the &lt;code&gt;src/components&lt;/code&gt; folder. Let’s call ours &lt;code&gt;header.component.ts&lt;/code&gt;, like for a blog post header. That file, at its very basic configuration, will look 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;{{ title }}&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;New Blog Post&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HeaderComponent&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Now that we have our component, let’s add it to our Astro template, in the &lt;code&gt;src/pages/index.astro&lt;/code&gt; file. This will be different from what you’re used to with Angular components. You’ll first need to import the component at the top of the file, inside the pair of triple dashes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
import { HeaderComponent } from '../components/header.component';
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, next to some of the other HTML in the astro file, add your new Angular component:&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;HeaderComponent&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Angular + Astro"&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;If you’ve used React, this will look more familiar. Also, make sure to provide a title as an input.&lt;/p&gt;

&lt;p&gt;After adding the component to your page, run the following command and open the site on the provided port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you open the page, you should see the content of your new component on the page, wherever it is that you added it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There is a lot of innovation happening in the Angular community recently, and because of it we are able to move forward and take advantage of new tools that the web development industry has to offer. Astro is beginning to grow, and as Angular developers we can now jump in and participate. I encourage you to go &lt;a href="https://dev.to/godspowercuche/bringing-angular-components-to-astro-islands-5h4b-temp-slug-273779"&gt;read this article by Brandon Roberts&lt;/a&gt; for more information on using Astro and Angular. You can also follow &lt;a href="https://analogjs.org/"&gt;Brandon’s project, Analog&lt;/a&gt;, to see more innovation in the Angular community&lt;/p&gt;

</description>
      <category>astro</category>
      <category>angular</category>
    </item>
    <item>
      <title>Reusable Component Pieces with ngTemplate Outlet</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Mon, 25 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/reusable-component-pieces-with-ngtemplate-outlet-3o0c</link>
      <guid>https://dev.to/prestonjlamb/reusable-component-pieces-with-ngtemplate-outlet-3o0c</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ng-template&lt;/code&gt;, &lt;code&gt;ng-container&lt;/code&gt;, and &lt;code&gt;ngTemplateOutlet&lt;/code&gt; provide the ability to reuse content inside an Angular component. Understanding what’s going on and how to use these methods allows a developer to build what they want without needing to duplicate parts of the template.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explanation of the Problem
&lt;/h2&gt;

&lt;p&gt;Have you ever needed to use &lt;code&gt;*ngIf&lt;/code&gt; in your template, and if the expression evaluates to false use a backup template? On top of that, maybe both situations (if the expression is true or false) require the same layout inside of the element that has the &lt;code&gt;*ngIf&lt;/code&gt; directive on it.&lt;/p&gt;

&lt;p&gt;I recently had came across this situation. We had some data that was being output in a list either had a link that stayed internal to the app or opened a link in a new tab external to the application. The content inside the links, however, always had the same layout. I didn’t want to duplicate the inner content, and luckily Angular provides the ability to accomplish this. The method includes using &lt;code&gt;ng-template&lt;/code&gt;, &lt;code&gt;ng-container&lt;/code&gt;, and &lt;code&gt;ngTemplateOutlet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before getting to the end solution, let’s look at an example of the data and how it’s output without using &lt;code&gt;ng-template&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ListComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;External&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://test.com&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;/code&gt;&lt;/pre&gt;

&lt;/div&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;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let link of links"&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;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"link.internal"&lt;/span&gt; &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ link.display }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&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;"!link.internal"&lt;/span&gt; &lt;span class="na"&gt;[attr.href]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ link.display }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this method, we have two &lt;code&gt;*ngIf&lt;/code&gt; directives on two separate &lt;code&gt;a&lt;/code&gt; tags, and the inner content of the link is the same in both cases. If that inner content changes, we have to make the change to both places or else there are inconsistencies in the layout. This is not ideal; we are repeating ourselves and there are multiple locations where we can introduce bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Angular provides a much more elegant solution to our problem. Our TypeScript code from above will remain the same, but we can have a lot less duplication in the HTML by using a couple special Angular tags. First I’ll show the HTML, and then we’ll discuss the different pieces.&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;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let link of links"&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;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"link.internal; else externalLink"&lt;/span&gt; &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&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;"linkLayout"&lt;/span&gt;
        &lt;span class="na"&gt;[ngTemplateOutletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ link: link }"&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;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#externalLink&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;[attr.href]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&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;"linkLayout"&lt;/span&gt;
          &lt;span class="na"&gt;[ngTemplateOutletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ link: link }"&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;/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;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#linkLayout&lt;/span&gt; &lt;span class="na"&gt;let-link=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ link.display }}&lt;span class="nt"&gt;&amp;lt;/span&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;There’s a lot going on here, so let’s break it down. We’ll start with the &lt;code&gt;*ngIf&lt;/code&gt; on the &lt;code&gt;a&lt;/code&gt; tag.&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;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"link.internal; else externalLink"&lt;/span&gt; &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&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;"linkLayout"&lt;/span&gt;
    &lt;span class="na"&gt;[ngTemplateOutletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ link: link }"&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;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#externalLink&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;[attr.href]=&lt;/span&gt;&lt;span class="s"&gt;"link.url"&lt;/span&gt;&lt;span class="nt"&gt;&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;"linkLayout"&lt;/span&gt;
      &lt;span class="na"&gt;[ngTemplateOutletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ link: link }"&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;/a&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;The &lt;code&gt;*ngIf&lt;/code&gt; directive has an expression listed: if &lt;code&gt;link.internal&lt;/code&gt; evaluates to &lt;code&gt;true&lt;/code&gt;, then show this &lt;code&gt;a&lt;/code&gt; tag. If it’s false, output the &lt;code&gt;ng-template&lt;/code&gt; tag that’s referenced by the &lt;code&gt;externalLink&lt;/code&gt; local template variable. This is how we can either navigate to a new route that’s part of the Angular app or external to the app. This is a method that can be used in any situation where your &lt;code&gt;*ngIf&lt;/code&gt; needs an &lt;code&gt;else&lt;/code&gt; clause.&lt;/p&gt;

&lt;p&gt;Next up, let’s look at what’s going on with the &lt;code&gt;ng-container&lt;/code&gt; inside both of the &lt;code&gt;a&lt;/code&gt; tags in the example.&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;ng-container&lt;/span&gt;
  &lt;span class="na"&gt;[ngTemplateOutlet]=&lt;/span&gt;&lt;span class="s"&gt;"linkLayout"&lt;/span&gt;
  &lt;span class="na"&gt;[ngTemplateOutletContext]=&lt;/span&gt;&lt;span class="s"&gt;"{ link: link }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can read more about the &lt;code&gt;ng-container&lt;/code&gt; element in the &lt;a href="https://angular.io/api/core/ng-container"&gt;Angular docs&lt;/a&gt;, but at a high level it’s a special element that can hold structural directives without adding new elements to the DOM. It can also be used in situations like this, with the &lt;code&gt;ngTemplateOutlet&lt;/code&gt; structural directive. The &lt;code&gt;ngTemplateOutlet&lt;/code&gt; directive determines what &lt;code&gt;ng-template&lt;/code&gt; will be output on the page inside the &lt;code&gt;ng-container&lt;/code&gt;. The context for the template, or needed variables, can be declared with the &lt;code&gt;ngTemplateOutletContext&lt;/code&gt; directive. In the above case, we are saying that the &lt;code&gt;#linkLayout&lt;/code&gt; content should be output on the page, and that there should be a variable called &lt;code&gt;link&lt;/code&gt; that will be used inside the &lt;code&gt;ng-template&lt;/code&gt;. The contents of the ng-template tag can be placed anywhere in the HTML file, though I’ve placed them at the bottom in this example.&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;ng-template&lt;/span&gt; &lt;span class="na"&gt;#linkLayout&lt;/span&gt; &lt;span class="na"&gt;let-link=&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/assets/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ link.display }}&lt;span class="nt"&gt;&amp;lt;/span&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;This template will be output on the screen anywhere it’s referenced. In this case, inside both &lt;code&gt;a&lt;/code&gt; tags. If we want to change the layout inside the &lt;code&gt;a&lt;/code&gt; tags, we need only change this one spot in the HTML. Everything will be kept in sync, and we have fewer possibilities of inconsistencies in the component.&lt;/p&gt;

&lt;p&gt;There is one alternate way of declaring the &lt;code&gt;ngTemplateOutlet&lt;/code&gt;. The result will be the same as the method shown above.&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;ng-container&lt;/span&gt;
  &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"linkLayout; context: { link: link }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The above method limits the duplication to a certain degree, especially for the content inside the &lt;code&gt;a&lt;/code&gt; tag. The example here is a fairly simple layout. This method becomes more useful when the internal layout becomes more complicated. That inner layout is defined once and reused in multiple locations. You could create a new component if you wanted, but that can introduce complexity sometimes as well.&lt;/p&gt;

&lt;p&gt;Knowing how to use &lt;code&gt;ng-template&lt;/code&gt;, &lt;code&gt;ng-container&lt;/code&gt;, and &lt;code&gt;ngTemplateOutlet&lt;/code&gt; can allow you to effectively output the content of a component with minimal duplication&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Lifecycle Hooks</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Fri, 22 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/angular-lifecycle-hooks-52h4</link>
      <guid>https://dev.to/prestonjlamb/angular-lifecycle-hooks-52h4</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Each Angular component has a lifecycle that lasts from the time the component is added to the page until it is removed from the page. There are several times to hook into the lifecycle, where you can run some code necessary for the component. We’ll look at a few of the most common hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular Lifecycle Hooks
&lt;/h2&gt;

&lt;p&gt;Angular has several lifecycle hooks, which you can &lt;a href="https://angular.io/guide/lifecycle-hooks"&gt;view in detail on the docs&lt;/a&gt;. Here’s the list of hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ngOnChanges&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngOnInit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngDoCheck&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngAfterContentInit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngAfterContentChecked&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngAfterViewInit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngAfterViewChecked&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ngOnDestroy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of the above lifecycle hooks run at various times during the lifecycle of the component. Depending on your needs you can run code when those events occur. Some are more useful and more commonly used than others. Let’s look at some examples of the hooks which I believe are most useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;ngOnInit&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s start with what is likely the most common lifecycle hook, &lt;code&gt;ngOnInit&lt;/code&gt;. This hook is used to initialize certain information or data used in the component. It’s run once, after &lt;code&gt;ngOnChanges&lt;/code&gt; is run. If you’ve worked in an Angular component at all, you’ve likely seen and used &lt;code&gt;ngOnInit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is one main “gotcha” to remember with this lifecycle hook. If the component’s data is changed, but it remains on the screen, &lt;code&gt;ngOnInit&lt;/code&gt; does not run again. This includes when a component is used for a route in your app. Let’s say we have a &lt;code&gt;DetailComponent&lt;/code&gt; that shows the detail of a user. The &lt;code&gt;userId&lt;/code&gt; is pulled from the route params and the data is shown on the page. If you route to the detail of a new user, the data will need to change but &lt;code&gt;ngOnInit&lt;/code&gt; will not be run again, even though the route changes.&lt;/p&gt;

&lt;p&gt;Here’s a brief example of an &lt;code&gt;ngOnInit&lt;/code&gt; method:&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="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;results&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;_dataService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getResults&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;h2&gt;
  
  
  &lt;code&gt;ngOnChanges&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The next hook we’ll look at is &lt;code&gt;ngOnChanges&lt;/code&gt;. This hook is used to respond to changes to the data that’s passed in to a component. It is run any time the data-bound properties of the component change. The first time it's run is before &lt;code&gt;ngOnInit&lt;/code&gt; is run.&lt;/p&gt;

&lt;p&gt;A good use case for &lt;code&gt;ngOnChanges&lt;/code&gt; is when a component has some data passed in, and subsequent calculations need to be made with that data to display in the component. If you were to make the calculations in the &lt;code&gt;ngOnInit&lt;/code&gt; hook, the data would not update as you expect or desire when the inputs are changed. This is due to &lt;code&gt;ngOnInit&lt;/code&gt; only being run once.&lt;/p&gt;

&lt;p&gt;Here’s an example of what may happen in the &lt;code&gt;ngOnChanges&lt;/code&gt; method:&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="nx"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SimpleChanges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;total&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;inputOne&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;inputTwo&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;ngOnChanges&lt;/code&gt; hook takes an optional argument of type &lt;code&gt;SimpleChanges&lt;/code&gt;. Each attribute on the &lt;code&gt;SimpleChanges&lt;/code&gt; object has three attributes: &lt;code&gt;currentValue&lt;/code&gt;, &lt;code&gt;previousValue&lt;/code&gt;, and &lt;code&gt;firstChange&lt;/code&gt;. Those three attributes are included on an interface called &lt;code&gt;SimpleChange&lt;/code&gt;. These attributes are pretty self explanatory, and allow you to react however you need to in your components. The only attributes present on the &lt;code&gt;SimpleChanges&lt;/code&gt; object are ones that changed in that particular run. So, if &lt;code&gt;inputOne&lt;/code&gt; changes, but not &lt;code&gt;inputTwo&lt;/code&gt;, then the object would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputOne"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"previousValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currentValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"firstChange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the data in your component should be re-calculated when the inputs change, use the &lt;code&gt;ngOnChanges&lt;/code&gt; hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;ngAfterViewInit&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AfterViewInit&lt;/code&gt; hook allows you to respond when the component’s view and child views are visible on the screen. This hook runs just once, after the first time &lt;code&gt;ngAfterContentChecked&lt;/code&gt; is run.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ngAfterViewInit&lt;/code&gt; hook is perfect when you need to reference an element of the component’s template inside the TypeScript class. If you try and reference the element in the &lt;code&gt;ngOnInit&lt;/code&gt; hook, there is a good chance that the variable will still be &lt;code&gt;undefined&lt;/code&gt;. Waiting until the &lt;code&gt;ngAfterViewInit&lt;/code&gt; hook runs ensures that the element will be in the screen, provided it’s not been removed from the screen with the &lt;code&gt;*ngIf&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;Here’s an example of using the &lt;code&gt;ngAfterViewInit&lt;/code&gt; hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DemoComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterViewInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&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;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ngAfterViewInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&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;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ElementRef { ... }&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;h2&gt;
  
  
  &lt;code&gt;ngOnDestroy&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ngOnDestroy&lt;/code&gt; hook is run when Angular removes the component from the application. It can be used for cleanup of the component, including unsubscribing from long-lived observables or removing event handlers.&lt;/p&gt;

&lt;p&gt;It’s important to remember that Angular needs to remove the component from the app for the hook to run. If you refresh or close the browser tab, the component is technically removed from the browser, but Angular didn’t control the removal of the component. Thus, the &lt;code&gt;ngOnDestroy&lt;/code&gt; hook is not run.&lt;/p&gt;

&lt;p&gt;Here’s an example of using the &lt;code&gt;ngOnDestroy&lt;/code&gt; hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;subscription&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;someService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unsubscribe&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;ul&gt;
&lt;li&gt;Best practice is to subscribe to observables using the &lt;code&gt;async&lt;/code&gt; pipe. If you do that, there’s no need to clean up subscriptions in the &lt;code&gt;ngOnDestroy&lt;/code&gt; hook. However, some situations require you to subscribe to the observable in the TypeScript file and this will allow you to unsubscribe from the Observable and prevent memory leaks in your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In my experience, these are the most used lifecycle hooks. Understanding how they are used and in what situations will allow you to be most effective when writing your Angular apps. The other hooks I mentioned at the beginning of the article can also be helpful, but aren’t as common as the four covered here&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Typed Reactive Forms</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Wed, 20 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/angular-typed-reactive-forms-29c7</link>
      <guid>https://dev.to/prestonjlamb/angular-typed-reactive-forms-29c7</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Reactive forms in Angular are a convenient way to manage your forms and react to changes made by the user. One issue with them has been that the value of the form has not been typed. Because of this, you could improperly access a value from a form and not know until runtime. Angular v14 introduces typed reactive forms, and removes this potential issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Issue
&lt;/h2&gt;

&lt;p&gt;Let’s look at a sample reactive form declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&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;FormGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&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;This form has two controls, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt;. With untyped reactive forms, I could write the following (valid) code, which would cause an error at runtime:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstName&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;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&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;name&lt;/code&gt; value on the form is just a string, not an object, so I shouldn’t be able to access &lt;code&gt;.firstName&lt;/code&gt;. The reason I can in this example is because at some point in the API for reactive forms, &lt;code&gt;any&lt;/code&gt; was used in the type.&lt;/p&gt;

&lt;p&gt;Strongly typed reactive forms will change this behavior, however, and ensure that you only access the value of the form correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typed Reactive Forms
&lt;/h2&gt;

&lt;p&gt;Moving forward, creating reactive forms will allow for specifying the type of the value of the form and the controls. For example:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&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;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Preston Lamb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will create a new &lt;code&gt;FormControl&lt;/code&gt; with the automatically inferred type of &lt;code&gt;FormControl&amp;lt;string|null&amp;gt;&lt;/code&gt;. It can be null because by default, the &lt;code&gt;reset&lt;/code&gt; method on the &lt;code&gt;FormControl&lt;/code&gt; will set the value to &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want the value to be non-nullable, you can use the &lt;code&gt;initialValueIsDefault&lt;/code&gt; option when creating a &lt;code&gt;FormControl&lt;/code&gt;:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&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;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Preston Lamb&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="na"&gt;initalValueIsDefault&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name control can no longer be set to null; if it’s reset the value will go back to ‘Preston Lamb’ in this case (or whatever the initial value is set to).&lt;/p&gt;

&lt;p&gt;You can also explicitly set the type of a form control:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&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;FormControl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&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="na"&gt;initialValueIsDefault&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;email&lt;/code&gt; control has the same functionality as the above &lt;code&gt;name&lt;/code&gt; control, with the exception of the default value being an empty string.&lt;/p&gt;

&lt;p&gt;Another option for typing reactive forms is by providing an interface as the type for a &lt;code&gt;FormGroup&lt;/code&gt;. Consider the following:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&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;userForm&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;FormGroup&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&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;By typing the form like this, we ensure that no controls can be added or removed from the form. All the attributes of the interface that are not optional must be present on the form. Optional attributes of the interface can be added or removed later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Having type-safe forms in Angular apps is a good step in the right direction. The possibility of accessing an attribute that doesn’t exist, or setting the value of a control to an unsupported value, is removed if the form and its controls are typed. The developer experience of using reactive forms will be better with these types.&lt;/p&gt;

&lt;p&gt;You can start using typed forms as of Angular v14&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Standalone Components</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Mon, 18 Jul 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/angular-standalone-components-16ki</link>
      <guid>https://dev.to/prestonjlamb/angular-standalone-components-16ki</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;For years, Angular has been organized and built on top of modules. These modules grouped functionality inside your app. Components, pipes, services, and directives that had related purpose were grouped together and declared inside modules, which would need to be imported in another part of the app to be used. This pattern works, and the organization for your component is nice, but it does complicate learning Angular for the first time. To get started with an app, a beginner has to learn what a component is and what a module is and how they work together. This makes it more complicated to jump in and get started. Standalone components coming to Angular is a big step towards simplifying different parts of your app, and simplifying the learning process.&lt;/p&gt;

&lt;p&gt;Throughout this article I’ll use the term “standalone components”, but these same methods can be used with pipes, directives, guards, and other pieces of an Angular application that you would normally have to declare inside an NgModule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Standalone Components?
&lt;/h2&gt;

&lt;p&gt;A typical Angular component is created and added to the &lt;code&gt;declarations&lt;/code&gt; array of an NgModule. If the component is not added to the &lt;code&gt;declarations&lt;/code&gt; array, it cannot be used by any other components, whether inside that same module or another one (by importing the module in a separate one). Thus, we can see that components have been, up until now, tied to modules.&lt;/p&gt;

&lt;p&gt;Standalone components are named this way because they “stand alone” from NgModules. They do not need to be included in the &lt;code&gt;declarations&lt;/code&gt; array to be used in other places. Instead, the component itself is imported where it needs to be used. Now, components can be be created and used without an NgModule. You could, theoretically, build an entire application without a custom NgModule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Standalone Component
&lt;/h2&gt;

&lt;p&gt;Now that we know what standalone components are, let’s look at an example of one.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;{{ name | titlecase }}&amp;lt;/h1&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;`
    h1 {
      color: blue;
    }
  `&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;NameComponent&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;This component takes a &lt;code&gt;name&lt;/code&gt; as an input and then outputs it on the page while title casing the string. For the most part, it looks just like any other component you’ve created in an Angular application. There are just a couple differences. First, we need to designate the component as standalone, which is done in the &lt;code&gt;@Component&lt;/code&gt; decorator’s metadata with the &lt;code&gt;standalone: true&lt;/code&gt; key/value pair. The other part that looks different from past components you’ve created is that there is an &lt;code&gt;imports&lt;/code&gt; attribute in the metadata, where you can import NgModules and/or other standalone components to be used inside this component. In the above example, the &lt;code&gt;CommonModule&lt;/code&gt; is imported so the &lt;code&gt;titlecase&lt;/code&gt; pipe can be used.&lt;/p&gt;

&lt;p&gt;To use this standalone component somewhere else, it needs to be imported. It can be imported in an NgModule or in another standalone component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NameComponent&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;./app/name.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;NameComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;app-name *ngIf="name" [name]="name"&amp;gt;&amp;lt;/app-name&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppRootStandaloneComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preston lamb&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;h2&gt;
  
  
  Bootstrapping an Application from a Standalone Component
&lt;/h2&gt;

&lt;p&gt;In addition to creating normal standalone components that are used throughout the app, you can create a standalone component that is used to bootstrap the application. In the past, bootstrapping an application has been done by a module. That still works, and you can continue to use that method if you’d like. However, you can now use a standalone component as the root of the application. Let’s say we want to use the above &lt;code&gt;AppRootStandaloneComponent&lt;/code&gt; as our root component for our app, and want to start the app with that component. We could bootstrap the app with the following 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bootstrapApplication&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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ExampleStandaloneComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ref&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;// do some stuff&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is similar to bootstrapping an application with a module, but it is slightly different. Both ways work and you can choose the way that you prefer.&lt;/p&gt;

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

&lt;p&gt;Standalone components are currently in developer preview only in Angular v14. You can try them out now, but they are not quite ready for prime time. In the coming months, we will see these become stable and be more frequently used in Angular applications.&lt;/p&gt;

&lt;p&gt;Until then, it’ll be helpful to play with standalone components and understand what they are and how they’re used. If you’re a library developer, this may be especially helpful for you as you plan to upgrade your library&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Shared Cypress Assets in an Nx Workspace</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Mon, 16 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/shared-cypress-assets-in-an-nx-workspace-427d</link>
      <guid>https://dev.to/prestonjlamb/shared-cypress-assets-in-an-nx-workspace-427d</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Many times Nx workspaces have multiple applications, and being able to share custom Cypress commands between the end to end test projects. I spent several months manually copying these commands between the different projects, and would inevitably forget to update one when a change was made. Finally I decided to solve the problem and find a way to share the Cypress assets among the projects. This article will cover one way to do this.&lt;/p&gt;

&lt;p&gt;To follow along, you'll need an Nx workspace with at least one end to end project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Shared Assets Library
&lt;/h2&gt;

&lt;p&gt;Let's get started by creating a shared end to end assets library. This will be similar to creating any other library in an Nx workspace. The only potential difference will be the type of library you create. Nx provides a way to create Angular specific libraries, for example. In this case, we don't want to create a framework specific library. That can be accomplished with the following command:&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="nv"&gt;$ &lt;/span&gt;nx g @nrwl/workspace:library e2e-assets &lt;span class="nt"&gt;--directory&lt;/span&gt; shared
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a generic Nx workspace library called &lt;code&gt;e2e-assets&lt;/code&gt; and puts it in the &lt;code&gt;libs/shared&lt;/code&gt; directory. In this library we'll add custom Cypress commands which we can then use in all our end to end projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Custom Command File
&lt;/h2&gt;

&lt;p&gt;Let's now add a file that contains a custom Cypress command in our new shared library. This custom command will make it easier to select elements by the &lt;code&gt;data-cy&lt;/code&gt; HTML attribute. Create a file in the &lt;code&gt;e2e-assets/src/lib&lt;/code&gt; folder called &lt;code&gt;data-cy.commands.ts&lt;/code&gt;. Here are the contents of that file:&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;// data-cy.commands.ts&lt;/span&gt;

&lt;span class="c1"&gt;// load the global Cypress types&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;reference types="cypress" /&amp;gt;&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Chainable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Custom command to get elements by data-cy attribute.
     * @example cy.dataCy('greeting')
     */&lt;/span&gt;
    &lt;span class="nx"&gt;dataCy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Chainable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Element&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dataCy&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="nx"&gt;value&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[data-cy=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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 first two lines of the file load the types for Cypress and prevent errors from showing in your IDE. The next portion of the file essentially extends the Cypress object for your tests by declaring the new custom command. If you leave this out and try to use the &lt;code&gt;dataCy&lt;/code&gt; command you will get an error and the command will not work. The last line of the file is the code to actually add the custom command. The first argument to the &lt;code&gt;Cypress.Commands.add&lt;/code&gt; method is the name of the new command, and the second argument is a callback function that provides the functionality for the custom command.&lt;/p&gt;

&lt;p&gt;This custom command returns the &lt;code&gt;cy.get&lt;/code&gt; method and selects an element by the &lt;code&gt;data-cy&lt;/code&gt; HTML attribute. We'll look at how it's used later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing the Custom Command
&lt;/h2&gt;

&lt;p&gt;The next step is to import the new custom command so it can be used in our Cypress tests. The first import belongs in the &lt;code&gt;e2e-assets/src/index.ts&lt;/code&gt; file:&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;// e2e-assets/src/index.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lib/data-cy.commands&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the new command available when we import this library into our Cypress tests, which we'll do next. The second import belongs in the &lt;code&gt;app-e2e/src/support/index.ts&lt;/code&gt; file. By importing the library here, this new command will be available in the &lt;code&gt;app-e2e&lt;/code&gt; Cypress tests.&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;// app-e2e/src/support/index.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@my-org/shared/e2e-assets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you have imported your shared e2e assets library, you can use the new command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using The New Custom Command
&lt;/h2&gt;

&lt;p&gt;Here's an example of using the new custom command in a Cypress test:&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;// app-e2e/src/integration/test.ts&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should show the homepage&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataCy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;homepage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&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;If you didn't use this custom command, your test would 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="c1"&gt;// app-e2e/src/integration/test.ts&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should show the homepage&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[data-cy=homepage]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&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;There's not a big difference here, but speaking from experience it gets tiresome to repeat the attribute selector each time you need access to an element based on the &lt;code&gt;data-cy&lt;/code&gt; attribute. This simple custom command is much easier to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;One of the biggest benefits of Nx workspaces is the ability to share code between projects. It's natural to share code between Angular or React apps, but the same process can be used to share code for your Cypress end to end tests. It becomes especially useful the more apps you have in your workspace, and for more complicated Cypress commands&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>nx</category>
    </item>
    <item>
      <title>Authenticating Your App for Cypress Tests</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Wed, 20 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/authenticating-your-app-for-cypress-tests-aen</link>
      <guid>https://dev.to/prestonjlamb/authenticating-your-app-for-cypress-tests-aen</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Many Angular apps require the user to be authenticated before using the app. This can make writing and running Cypress end to end tests difficult. If your login flow requires you to leave the app to authenticate, the problem becomes even more difficult. This article will cover a solution to this problem and allow you to write your Cypress tests. The exact specifics of doing this will vary for each app, but each case should follow closely to the steps provided here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a login Cypress command&lt;/li&gt;
&lt;li&gt;Optionally, you can obtain a token from your auth server, and save it to localStorage (or sessionStorage, depending on your app)&lt;/li&gt;
&lt;li&gt;Run the login command in the &lt;code&gt;beforeEach&lt;/code&gt; hook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app I implemented this in was using the &lt;code&gt;angular-oauth2-oidc&lt;/code&gt; package for authentication, and our auth server is Identity Server 4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cypress Login Command
&lt;/h2&gt;

&lt;p&gt;The first step is to create a Cypress command that we can run to make the app believe the user is logged in. You can either use a fake token if you don't plan on calling the API or you can get a real token from the auth server. Below is an example of getting the token from the auth server and storing it in &lt;code&gt;localStorage&lt;/code&gt;. You may have to save the token in another location for 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;// authentication.commands.ts&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Chainable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/**
         * Custom command to setup login
         * @example cy.login()
         */&lt;/span&gt;
        &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Chainable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Element&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&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="o"&gt;=&amp;gt;&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authServerTokenUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client_secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grant_type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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="na"&gt;form&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&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="s1"&gt;Content-Type&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="s1"&gt;application/x-www-form-urlencoded&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id_token_claims_obj&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="cm"&gt;/* userInfo object */&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expires_at&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="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&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;Let's walk through the function together. The top portion of the code block, starting with &lt;code&gt;declare namespace Cypress&lt;/code&gt;, declares the login method as part of the Cypress object. If you don't declare the login method like this calling &lt;code&gt;cy.login()&lt;/code&gt; will result in an error. The next portion of the code block, starting with &lt;code&gt;Cypress.Commands.add&lt;/code&gt;, adds the new &lt;code&gt;login&lt;/code&gt; command to be used in your Cypress tests. An &lt;code&gt;options&lt;/code&gt; object is created for making a call to the auth server to get a token. The request is made, and because it's a promise we can chain a &lt;code&gt;.then&lt;/code&gt; method on to the request and get the returned data inside the callback. In my case, the token comes back on the &lt;code&gt;response.body&lt;/code&gt; object as the &lt;code&gt;access_token&lt;/code&gt;. Our app uses &lt;code&gt;localStorage&lt;/code&gt; for storing the token so I store the token on &lt;code&gt;window.localStorage&lt;/code&gt;. I also set the &lt;code&gt;expires_at&lt;/code&gt; value and the user's info object. You may want to chain a &lt;code&gt;.catch&lt;/code&gt; method on to the request where you can catch errors and log what happens. This will help you debug if the request fails.&lt;/p&gt;

&lt;p&gt;All these values may have different keys in your application, but you'll likely need to set each value. I figured out which values were needed by logging in to the app and opening &lt;code&gt;localStorage&lt;/code&gt;. I was able to see which values the auth package set in &lt;code&gt;localStorage&lt;/code&gt; and then by process of elimination found the ones that were required for the user to be authenticated when the app loads.&lt;/p&gt;

&lt;p&gt;If you want to use a fake token, you can remove everything from the &lt;code&gt;login&lt;/code&gt; command except where the &lt;code&gt;localStorage&lt;/code&gt; values are set. This method will work just fine if you don't plan on calling the application's API for any data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the &lt;code&gt;login&lt;/code&gt; Command
&lt;/h2&gt;

&lt;p&gt;The next step is to actually use the &lt;code&gt;login&lt;/code&gt; command you created. There are a couple of ways to do this, but the best way is to call the command in the &lt;code&gt;beforeEach&lt;/code&gt; hook of your spec file.&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;// home.spec.ts&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;beforeEach&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// other test setup&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// e2e tests&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After I first created the &lt;code&gt;login&lt;/code&gt; command I tried calling it in a &lt;code&gt;before&lt;/code&gt; hook instead of &lt;code&gt;beforeEach&lt;/code&gt;. That worked for the first test in the spec file, but &lt;code&gt;localStorage&lt;/code&gt; is cleared by Cypress after each test. Because of that the app was no longer authenticated after the first test. Thus, make sure to call the login command in the beforeEach hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cypress Environment Variables
&lt;/h2&gt;

&lt;p&gt;Cypress has &lt;a href="https://docs.cypress.io/guides/guides/environment-variables"&gt;multiple ways that you can provide environment variables&lt;/a&gt; to use in your tests. There are a lot of ways to provide the environment variables you need to request the token, but I used the &lt;code&gt;cypress.env.json&lt;/code&gt; file when running the tests on my local machine and provided the values on the command line when running the tests in our CI/CD pipeline. The &lt;code&gt;cypress.env.json&lt;/code&gt; file is not committed to our git repo so that the secrets are not accidentally made public.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It took me a few hours to figure out the specifics of how to make the app believe the user was logged in, but this method works perfectly. We can mock all the data from the API and use a fake token, or we can use a real token and call our actual API&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Detecting Idle Users in Your Angular App</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Tue, 19 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/detecting-idle-users-in-your-angular-app-54be</link>
      <guid>https://dev.to/prestonjlamb/detecting-idle-users-in-your-angular-app-54be</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;Occasionally the applications we work on need to react in a particular way if the user is inactive for a certain amount of time. For example, if the user is inactive for 5 minutes a popup should appear and ask the user if they want to stay logged in or if they want to log out. In this article, we'll look at a way to do that in your Angular app. We'll use two libraries to do this: &lt;code&gt;@ng-idle/core&lt;/code&gt; and &lt;code&gt;@ng-idle/keepalive&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting Idle Users
&lt;/h2&gt;

&lt;p&gt;To get started, let's import the necessary modules into the root &lt;code&gt;AppModule&lt;/code&gt;:&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;// app.module.ts&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;NgIdleKeepaliveModule&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;@ng-idle/keepalive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;NgIdleKeepaliveModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&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;Importing the &lt;code&gt;NgIdleKeepaliveModule&lt;/code&gt; will get your application set up and ready to detect idle users. Next up, let's jump into the &lt;code&gt;AppComponent&lt;/code&gt;, where the majority of the work will be done. We'll need to initialize a couple settings from the &lt;code&gt;core&lt;/code&gt; module. Let's take a look, and then discuss.&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;// app.component.ts&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;DEFAULT_INTERRUPTSOURCES&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;@ng-idle/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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;numberOfSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Idle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setIdle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberOfSeconds&lt;/span&gt;&lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberOfSeconds&lt;/span&gt;&lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setInterrupts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_INTERRUPTSOURCES&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;Let's look at these lines in a little more detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;setIdle&lt;/code&gt; method sets the amount of time to wait before determining that the user is idle. The value is provided in seconds. During this time, the application won't do anything with the idle user. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;setTimeout&lt;/code&gt; method determines how long the timeout lasts. In other words, using the example above, the application will wait 5 seconds before determining that the user is idle. At that point, the user will have 5 seconds (the length of the timeout) to register some activity in the application before the timeout expires. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;setInterrupts&lt;/code&gt; method takes an array of Events. These events interrupt the timeout and start it over. The defaults include &lt;code&gt;mousemove&lt;/code&gt;, &lt;code&gt;keydown&lt;/code&gt;, &lt;code&gt;DOMMouseScroll&lt;/code&gt;, &lt;code&gt;mousewheel&lt;/code&gt;, &lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;touchstart&lt;/code&gt;, &lt;code&gt;touchmove&lt;/code&gt; and &lt;code&gt;scroll&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After these initialization values are set, we'll need to know when we should show or hide the warning or log the person out. I'll show you what I think are the most important events we'll listen to.&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;// app.component.ts&lt;/span&gt;

&lt;span class="nx"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setIdle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberOfSeconds&lt;/span&gt;&lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberOfSeconds&lt;/span&gt;&lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setInterrupts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_INTERRUPTSOURCES&lt;/span&gt;&lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onIdleStart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;// show the modal&lt;/span&gt;
    &lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onIdleEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;// hide the modal&lt;/span&gt;
    &lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onTimeoutWarning&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;secondsLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;// Update the warning message&lt;/span&gt;
    &lt;span class="p"&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;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;// Hide the modal, log out, do something else&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;Let's talk about each of these events in more detail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;onIdleStart&lt;/code&gt; method fires when the user becomes idle. This is after the &lt;code&gt;numberOfSeconds&lt;/code&gt; passed in to the &lt;code&gt;setIdle&lt;/code&gt; method. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;onIdleEnd&lt;/code&gt; event fires when the user is no longer idle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onTimeoutWarning&lt;/code&gt; fires each second for the duration that was provided to the &lt;code&gt;setTimeout&lt;/code&gt; method. So, if you set that value at 5, the &lt;code&gt;onTimeoutWarning&lt;/code&gt; will fire at 5, 4, 3, 2, and 1. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;onTimeout&lt;/code&gt; event fires when the specified amount of time has expired. This amount of time is the &lt;code&gt;setIdle&lt;/code&gt; amount and &lt;code&gt;setTimeout&lt;/code&gt; amounts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the above code in place, you should have everything you need to determine if a user is idle or not, and then to react to them timing out. The last step is to start the service that watches for the idle users. You can do that with the &lt;code&gt;watch&lt;/code&gt; method:&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="nx"&gt;ngOnInit&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;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watch&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;watch&lt;/code&gt; method starts the service and watches for the actions listed above. If you don't call this method, nothing will occur in the app and you'll definitely be left frustrated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you need to stop the timer, you can call the &lt;code&gt;stop&lt;/code&gt; method if you want to turn the service off and stop watching for idle users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This method of watching for idle users was a quick and easy way to accomplish the task. With this, I was able to wait until a user had been idle for a certain amount of time and then log them out if they remained idle. There are other things you could do as well, depending on your use case.&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Share Interfaces in Angular and NestJS with Nx</title>
      <dc:creator>Preston Lamb</dc:creator>
      <pubDate>Tue, 04 Jan 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/prestonjlamb/share-interfaces-in-angular-and-nestjs-with-nx-1alj</link>
      <guid>https://dev.to/prestonjlamb/share-interfaces-in-angular-and-nestjs-with-nx-1alj</guid>
      <description>&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;p&gt;I'm a big fan of using Nx and having multiple apps in a single workspace, especially when the apps have a lot in common and a lot of code to share. This is especially helpful when dealing with interfaces for data retrieved from or sent to the server. In this article, we'll talk about how to share those interfaces between the front and back end.&lt;/p&gt;

&lt;p&gt;This isn't the only way to manage these interfaces, but it is working well for us on a full stack project in our Nx workspace. An update can be made to the interface in one spot, and the front and back ends stay in sync. I've worked on a lot of projects where the communication breaks down and it's unclear what data should be sent or expected. That stumbling block can be eliminated by having your front and back end apps in the same workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;If you want to follow along, create a new Nx workspace:&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="nv"&gt;$ &lt;/span&gt;npx create-nx-workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give the workspace a name, and then select the angular-nest option for creating the workspace. After that you can enter what you want for the remainder of the prompts. Once the dependencies are installed, you should be good to go.&lt;/p&gt;

&lt;p&gt;When you open the project, you'll see a couple directories inside the apps directory. The three directories are &lt;code&gt;api&lt;/code&gt;, your Angular app folder, and the Angular app's end to end test folder. In the libs directory is an &lt;code&gt;api-interfaces&lt;/code&gt; lib.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Interface
&lt;/h2&gt;

&lt;p&gt;Let's create our first interface. It'll be a simple example, one that's frequently used: a todo. In the &lt;code&gt;api-interfaces&lt;/code&gt; lib, create a new file called &lt;code&gt;todo.interface.ts&lt;/code&gt; next to the &lt;code&gt;api-interfaces.ts&lt;/code&gt; file that was created automatically when the workspace was created. Put the following contents in the new file:&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;// todo.interface.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;This will be the base interface for the todos in our app. The Angular app will use this interface for type checking, and the API will implement this interface for the entities and DTOs that are used in NestJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a DTO
&lt;/h2&gt;

&lt;p&gt;Now that we have an interface, let's create a DTO that our NestJS app can use to define the data that should be sent when creating a new todo or updating an existing one. In the &lt;code&gt;api&lt;/code&gt; app, create a new file: &lt;code&gt;todo.dto.ts&lt;/code&gt; and add the following:&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;// create-todo.dto.ts&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;Todo&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;@my-workspace/api-interfaces

export class CreateTodoDto implements Omit&amp;lt;Todo, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt; {
    title: string;
    completed: boolean;
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: in all likelihood you will not create this DTO in the &lt;code&gt;api&lt;/code&gt; app, but in a new lib that you create for this NestJS module. To keep things simple for this demo, though, I selected the &lt;code&gt;api&lt;/code&gt; folder to contain the DTOs and entities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a couple things I want to point out here. First, we import our &lt;code&gt;Todo&lt;/code&gt; interface from the &lt;code&gt;api-interfaces&lt;/code&gt; lib, the one we created in the last section. This is the base for the DTO. We &lt;code&gt;implement&lt;/code&gt; the interface to create our &lt;code&gt;CreateTodoDto&lt;/code&gt;, but we use &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys"&gt;the &lt;code&gt;Omit&lt;/code&gt; utility type&lt;/a&gt; to remove the &lt;code&gt;id&lt;/code&gt; attribute from the DTO. The reason for this is because we won't have an &lt;code&gt;id&lt;/code&gt; for the todo when we're creating it; that will be determined by the database. By using the &lt;code&gt;Omit&lt;/code&gt; utility type and removing the &lt;code&gt;id&lt;/code&gt; attribute from the DTO, we don't need to pass a &lt;code&gt;null&lt;/code&gt; &lt;code&gt;id&lt;/code&gt; when creating a new todo while at the same time requiring all the other attributes.&lt;/p&gt;

&lt;p&gt;With this DTO now created, we can tell the controller what type to expect when a new todo is created. If an object with more or less attributes is passed to the endpoint, we can return a 400 with the required fields on the object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Entity
&lt;/h2&gt;

&lt;p&gt;Creating the entity is similar to the DTO, but we won't need to use the &lt;code&gt;Omit&lt;/code&gt; utility type. Here's an example of the entity:&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;// todo.entity.ts&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;Todo&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;@my-workspace/api-interfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PrimaryGeneratedColumn&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;typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;TodoEntity&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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 implementation here is very similar to the DTO, but we don't leave out the &lt;code&gt;id&lt;/code&gt;. Instead, we mark it as the primary key and set it to be auto generated when a new todo is created. The other difference is the &lt;code&gt;@Entity()&lt;/code&gt; decorator. This is required by &lt;code&gt;typeorm&lt;/code&gt; to make this a table in the database where todos can be saved. Also, because the class is defined as &lt;code&gt;TodoEntity&lt;/code&gt;, the table would be called &lt;code&gt;todo_entity&lt;/code&gt; by default. By providing a string inside the parentheses for the &lt;code&gt;Entity&lt;/code&gt; decorator, we can set the table name to &lt;code&gt;todo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I like to call the entity &lt;code&gt;TodoEntity&lt;/code&gt; so that it's clear when I'm using it in different files that I am not using the interface. There are other ways, however, to distinguish between the two files and objects. Do whatever feels best to you!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits
&lt;/h2&gt;

&lt;p&gt;So we just created three files for todos in our app. What's the benefit? Well, Angular is more powerful when types or interfaces or classes are used to determine how the data in your app is organized. You get auto completion from your IDE, and you're less likely to use the wrong attribute or method. In addition, with NestJS as our backend, we can easily check that the data that's sent to the backend is shaped correctly so that we don't have server errors popping up because too many attributes (or not enough) are sent along with the request.&lt;/p&gt;

&lt;p&gt;The hard part is when you want or need these files on both the front end and the back end. Many times, those applications are in different repositories and managed by different teams. By having both applications in the same workspace, we've closed that gap. And, by having the DTO and entity implement the interface, we're assured that if the interface changes then changes will need to be made to the DTO and entity. Those two files will have errors if attributes are added or removed to the interface and they don't implement the right attributes. Thus, the shape of the data is always the same on the front and back end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this article helped you with knowing how you can manage the interfaces, DTOs and entities in your application. When starting this project, I was unsure of the best way to do this same thing. I got &lt;a href="https://twitter.com/prestonjlamb/status/1425934473560870912"&gt;some ideas from Twitter&lt;/a&gt;, and then just started trying it out and came up with this method. I know there are other ways to do it; maybe even better ways. But this was a simple implementation and has worked great so far. Let me know how it goes for you&lt;/p&gt;

</description>
      <category>angular</category>
      <category>nestjs</category>
      <category>nx</category>
    </item>
  </channel>
</rss>
