<?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: Kyler Johnson</title>
    <description>The latest articles on DEV Community by Kyler Johnson (@kylerjohnsondev).</description>
    <link>https://dev.to/kylerjohnsondev</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%2F315115%2F395d9bd9-6e12-46ff-a6cf-11c4c25bbc94.jpg</url>
      <title>DEV Community: Kyler Johnson</title>
      <link>https://dev.to/kylerjohnsondev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kylerjohnsondev"/>
    <language>en</language>
    <item>
      <title>Basic Reactive Patterns in Angular</title>
      <dc:creator>Kyler Johnson</dc:creator>
      <pubDate>Thu, 14 May 2020 22:12:03 +0000</pubDate>
      <link>https://dev.to/kylerjohnsondev/basic-reactive-patterns-in-angular-7n5</link>
      <guid>https://dev.to/kylerjohnsondev/basic-reactive-patterns-in-angular-7n5</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuz16vi1dnzmjeqxzp6z3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuz16vi1dnzmjeqxzp6z3.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular version: 6 or later
RxJS versions: 5.5 or later
Node Version: 10.9 or later
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to write performant, maintainable Angular apps, RxJS knowledge is absolutely necessary. In this article, my goal is to help Angular developers leverage the reactive paradigm with RxJS in a clean, readable way by going over some common reactive patterns. This is not intended to be a comprehensive guide, but a foundation on which developers can continue to build their understanding.&lt;/p&gt;

&lt;p&gt;We will take a look at the following real-world scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting data from a service&lt;/li&gt;
&lt;li&gt;Reading route parameters and using them to fetch data from a service&lt;/li&gt;
&lt;li&gt;Managing multiple observable streams in a component&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Note about Subscribing
&lt;/h2&gt;

&lt;p&gt;Before we get into those scenarios, let's talk briefly about how we are going to subscribe to our observables. In general, if we explicitly subscribe using the &lt;code&gt;subscribe&lt;/code&gt; function, we would then have to properly manage our subscriptions ourselves, which involves knowing when we need to subscribe/unsubscribe and writing the code to do it. Another thing to keep in mind is that even if we know how to properly manage these subscriptions, every developer working on our project may not. Instead, we're going to leverage the framework to do all of that for us by using the &lt;code&gt;async&lt;/code&gt; pipe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: While I don't recommend that you use in-line templating in your Angular components, I'm going to do that here for the sake of brevity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Data from a Service
&lt;/h2&gt;

&lt;p&gt;Here, we will take a look at how to fetch data from a server and display it on the screen. We have a &lt;code&gt;fetchCoffeeList&lt;/code&gt; function in our service that uses Angular's HttpClient to make a call to the server and wrap the response in an observable and returns it.&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;// coffee.service.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

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

    &lt;span class="nf"&gt;fetchCoffeeList&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Coffee&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`coffee.com/coffee/list`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&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;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Coffee&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;url&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;In the typescript file of our coffee component, we set our &lt;code&gt;coffees$&lt;/code&gt; property equal to the result of our service call. Because we're returning an observable, our service call doesn't execute until it has a subscriber. When our &lt;code&gt;CoffeeComponent&lt;/code&gt; initializes, the async pipe automatically subscribes to the &lt;code&gt;coffees$&lt;/code&gt; observable. When the payload comes back from the server, the observable emits a new value containing the payload and our component renders the data. When the component is destroyed, the async pipe automatically unsubscribes from &lt;code&gt;coffees$&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;// coffee.component.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="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-coffee&lt;/span&gt;&lt;span class="dl"&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;ng-container *ngIf="coffees$ | async as coffees"&amp;gt;
            &amp;lt;ul&amp;gt;
                &amp;lt;li *ngFor="let coffee of coffees"&amp;gt;{{ coffee.name }}&amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
        &amp;lt;/ng-container&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeComponent&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="nx"&gt;coffees$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Coffee&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;coffeeService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CoffeeService&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;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&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;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&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;coffees$&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;coffeeService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchCoffeeList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;span class="nx"&gt;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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/error&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
           &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; &lt;code&gt;HttpClient&lt;/code&gt; &lt;em&gt;request methods automatically complete for us when they get a response from the server so it wouldn't actually cause a memory leak if we didn't unsubscribe here; however, it's a good idea to be consistent in the way we subscribe across our app.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;

&lt;p&gt;In the snippet above, we are piping onto the observable we get back from the &lt;code&gt;fetchCoffeeList&lt;/code&gt; method and inside of the pipe, we're using the &lt;code&gt;catchError&lt;/code&gt; operator from RxJS to catch any errors that are thrown. We can think of it as a try/catch for our observable stream. &lt;code&gt;catchError&lt;/code&gt; will catch any error that is thrown from the source observable or inside of any other operators in the pipe. For this example and the others, we're just going to log the error and navigate to an error page, passing the error message as a route parameter. For more about error handling, take look at this &lt;a href="https://blog.angular-university.io/rxjs-error-handling/" rel="noopener noreferrer"&gt;article&lt;/a&gt; from Angular University.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Route Parameters to Fetch Data
&lt;/h2&gt;

&lt;p&gt;First, let's talk about the use case for this. Let's say we have a list of coffees displayed on the screen and we want to click on one and go to a "detail" page that shows the ingredients and nutritional info for that coffee. In this scenario, when a coffee is clicked, we pass the id of that coffee in as a parameter. The route configuration for our "detail" page would be setup to accept a parameter of &lt;code&gt;coffeeId&lt;/code&gt;. When our &lt;code&gt;CoffeeDetailsComponent&lt;/code&gt; initializes, we need to get the route parameter and fetch the coffee details by coffee id in order to display them. In this section, we're going to talk about how to do this reactively.&lt;/p&gt;

&lt;p&gt;Following the pattern from the previous section, let's look at the service method first. Here, we simply have a service method that makes an API call to get the coffee details.&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;// coffee-details.service.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeDetailsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

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

    &lt;span class="nf"&gt;getByCoffeeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coffeeId&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="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CoffeeDetails&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coffee.com/coffee/detail&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coffeeId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coffeeId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;return&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;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CoffeeDetails&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;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&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;When the &lt;code&gt;CoffeeDetailsComponent&lt;/code&gt; intializes, we susbscribe to the the &lt;code&gt;coffeeDetails$&lt;/code&gt; observable using the async pipe, which gets its value from the results of the RxJS &lt;code&gt;pipe&lt;/code&gt; method. The &lt;code&gt;pipe&lt;/code&gt; method takes one or more &lt;a href="https://rxjs.dev/guide/v6/pipeable-operators" rel="noopener noreferrer"&gt;RxJS "pipeable operators"&lt;/a&gt; in order to transform data. In our case, the &lt;code&gt;ParamMap&lt;/code&gt; is passed by context into it and a &lt;code&gt;CoffeeDetails&lt;/code&gt; object wrapped in an observable is the expected result.&lt;/p&gt;

&lt;p&gt;So how can we start with a &lt;code&gt;ParamMap&lt;/code&gt; and end up with an &lt;code&gt;Observable&amp;lt;CoffeeDetails&amp;gt;&lt;/code&gt;? Well, we need a transformation to occur so we use a RxJS transformation operator called &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/switchMap" rel="noopener noreferrer"&gt;switchMap&lt;/a&gt;. In the example below, we're getting our &lt;code&gt;coffeeId&lt;/code&gt; from the map object by key, parsing it to a number type, and passing it into the service method that fetches coffee details. The &lt;code&gt;switchMap&lt;/code&gt; operator will susbscribe to our service method and return the result. Because we know that the return value of our service method is &lt;code&gt;Observalbe&amp;lt;CoffeeDetails&amp;gt;&lt;/code&gt;, we know that the return value of the &lt;code&gt;switchMap&lt;/code&gt; operator is going to be &lt;code&gt;Observable&amp;lt;CoffeeDetails&amp;gt;&lt;/code&gt;, too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="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-coffee-details&lt;/span&gt;&lt;span class="dl"&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;div *ngIf="coffeeDetails$ | async as details"&amp;gt;
            &amp;lt;section class="nutrition-info&amp;gt;
                &amp;lt;p&amp;gt;{{ details.nutrition.totalCalories }}&amp;lt;p&amp;gt;
            &amp;lt;/section&amp;gt;
            &amp;lt;section class="ingredients"&amp;gt;
                &amp;lt;ul&amp;gt;
                    &amp;lt;li *ngFor="let ingredient of details.ingredients"&amp;gt;
                        {{ ingredient }}
                    &amp;lt;/li&amp;gt;
                &amp;lt;/ul&amp;gt;
            &amp;lt;/section&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeDetailsComponent&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="nx"&gt;coffeeDetails$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CoffeeDetails&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;coffeeDetailsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CoffeeDetailsService&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;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRoute&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;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&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;coffeeDetails$&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;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paramMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ParamMap&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;coffeeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;coffeeId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&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;coffeeDetailsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByCoffeeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coffeeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;span class="nx"&gt;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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/error&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
           &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;note: the&lt;/em&gt; &lt;code&gt;switchMap&lt;/code&gt; &lt;em&gt;operator manages only one subscription at a time. When the source observable emits a new value, it cancels the previous inner observable (even if an HTTP request is in-flight) and creates a new observable and subscribes to it. This works perfectly for this use case because if the user clicks on another coffee before the detail view of this one loads, the previous request gets cancelled and it re-executes with the new route parameter. This can cause unexpected issues if used in certain situations, though. We don't want requests to be cancelled when we're doing things like database writes. For things like that concatMap would be a better choice.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Multiple Observable Streams
&lt;/h2&gt;

&lt;p&gt;So what about when our component has to manage multiple observable streams? Subscribing to each observable individually, even with the async pipe, can can significantly impact performance. This is because each time one of the observable streams emit a new value, change detection fires to update the UI. We can solve this problem by using the &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/combineLatest" rel="noopener noreferrer"&gt;combineLatest&lt;/a&gt; operator to create a view model for our component template.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;combineLatest&lt;/code&gt; belongs to a category of &lt;a href="https://rxjs-dev.firebaseapp.com/guide/operators" rel="noopener noreferrer"&gt;RxJS operators&lt;/a&gt; known as the join creation operators, so-called because they take in mutiple source observables and create a single observable stream to output. You can think of single observable output as a view model for your component template. &lt;code&gt;combineLatest&lt;/code&gt; is unique in that it doesn't emit its first value until all of its source observables have emitted at least one value. In other words, when we use this to combine multiple observables in our component, we don't attempt to render the UI until we have all the data it depends on. This means that change detection only has to fire once to initially render the component UI.&lt;/p&gt;

&lt;p&gt;Let's take a look at some code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// coffee-sales.service.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeSalesService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

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

    &lt;span class="nf"&gt;fetchYearToDateSales&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SalesMetrics&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`coffee.com/sales/ytd`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&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;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SalesMetrics&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;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;fetchTodaysSales&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SalesMetrics&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`coffee.com/sales/today`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&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;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SalesMetrics&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;url&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 typescript"&gt;&lt;code&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-coffee-sales&lt;/span&gt;&lt;span class="dl"&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;div *ngIf="vm$ | async as vm"&amp;gt;
            &amp;lt;app-ytd-sales 
               [yearToDateSales]="vm.yearToDateSales"&amp;gt;
            &amp;lt;/app-ytd-sales&amp;gt;
            &amp;lt;app-daily-sales 
               [todaysSales]="vm.todaysSales"&amp;gt;
            &amp;lt;/app-daily-sales&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoffeeSalesComponent&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="nx"&gt;vm$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;yearToDateSales&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SalesMetrics&lt;/span&gt;
        &lt;span class="na"&gt;todaysSales&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SalesMetrics&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;salesService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CoffeeSalesService&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;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Logger&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&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;vm$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&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;salesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchYearToDateSales&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;salesService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchTodaysSales&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// array -&amp;gt; object using object destructuring&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;yearToDateSales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todaysSales&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;yearToDateSales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todaysSales&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
            &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;span class="nx"&gt;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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/error&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
           &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: combineLatest takes in an array of observables and outputs a single observable containing an array of the latest emitted values of the source observables. Handling an array in the UI wouldn't be very readable so we use object destructuring to map that array to an object servicing as our view model.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So when our component initializes, we subscribe to our &lt;code&gt;vm$&lt;/code&gt; property using the async pipe and &lt;code&gt;combineLatest&lt;/code&gt; is executed. It takes an array of observables and outputs an observable containing an array of values. The first value in the array is the latest value from the first observable in the array of observables we passed into it (orderQueue) while the second value in the array corresponds to the second observable (todaysSales). Then, we pipe onto the result and use the RxJS &lt;code&gt;map&lt;/code&gt; operator to transform our array into a view model object using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring" rel="noopener noreferrer"&gt;object destructuring&lt;/a&gt; syntax.&lt;/p&gt;

&lt;p&gt;Think about the file containing the component class (ex. coffee-sales.component.ts) as a "controller" class. Its sole responsibilty is to build the data structure the UI needs. Any data transformations/manipulations should happen here.&lt;/p&gt;

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

&lt;p&gt;My goal with this article is to provide a quick reference for some common reactive patterns to help Angular developers leverage the reactive paradigm and improve the performance and maintainability of their applications.&lt;/p&gt;

&lt;p&gt;Key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Subscribe to your observables using the async pipe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;switchMap&lt;/code&gt; operator when you only care about the action completing based on the latest value of the source observable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Minimize change detection cycles on component initialization by using &lt;code&gt;combineLatest&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make use of pipeable operators like &lt;code&gt;map&lt;/code&gt; to do any data transformation/manipulations inside of your component class&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>reactive</category>
    </item>
    <item>
      <title>Build your Angular App Once, Deploy Anywhere</title>
      <dc:creator>Kyler Johnson</dc:creator>
      <pubDate>Sat, 11 Jan 2020 22:12:03 +0000</pubDate>
      <link>https://dev.to/kylerjohnsondev/build-your-angular-app-once-deploy-anywhere-5ggk</link>
      <guid>https://dev.to/kylerjohnsondev/build-your-angular-app-once-deploy-anywhere-5ggk</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EVHYITfB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./gears.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EVHYITfB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./gears.png" alt="Gears Image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular version: 8.x 
Node Version: 10.9 or later
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  The Ideal Scenario
&lt;/h2&gt;

&lt;p&gt;We're building an Angular application and when we merge new code into the master branch of our git repo, we want our build tool (like Jenkins) to grab the latest code and build our deployment package for us. With our deployment package built (A.K.A the &lt;code&gt;dist&lt;/code&gt; folder), we want to head over to our deployment tool (like Octopus), select an environment to which we want to deploy our app, click a "deploy" button, and trust it to deploy our package, replacing our envrionment variables in a config file with values specific to the selected environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Do We Need to Achieve This?
&lt;/h2&gt;

&lt;p&gt;We need a configuration file that we can access from our Angular code at runtime - which means it has to exist in the &lt;code&gt;dist&lt;/code&gt; folder we intend to deploy. We need it there because we want to configure our deployment tool to replace the values of the environment variables within with values specific to the environment we deploy to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Angular's Environment Files Are Not The Solution
&lt;/h2&gt;

&lt;p&gt;Let's say we are using the &lt;em&gt;environment&lt;/em&gt; files for our configuration as described &lt;a href="https://angular.io/guide/build"&gt;here&lt;/a&gt;. If we run &lt;code&gt;ng build&lt;/code&gt; and look inside of the &lt;code&gt;dist&lt;/code&gt; folder, we do not see any of the environment files there. Because this is a compile-time solution, the configuration settings in the environment files are pulled into the minified JS bundles in the &lt;code&gt;dist&lt;/code&gt; folder. We cannot easily configure our build tool to edit our environment variables if we cannot point it toward a file to edit. In short, this does not work with the "build once, deploy anywhere" model. To do this, our app needs to resolve configuration data at runtime instead of compile time. &lt;/p&gt;

&lt;h2&gt;
  
  
  So What Do We Do?
&lt;/h2&gt;

&lt;p&gt;Luckily, there is a rather quick solution. All we have to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a JSON configuration file in the &lt;code&gt;src&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Update our angular/webpack configuration to include the file in our &lt;code&gt;dist&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Add a simple configuration service with a call to get our config data from our config file&lt;/li&gt;
&lt;li&gt;Use APP_INITIALIZER to invoke the method retrieving our config data during the bootstrap process&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Side note: Placing our configuration in a JSON file makes configuring our deployment tool easier because many of them (like Octopus) have native support for replacing values in JSON files.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the config file
&lt;/h3&gt;

&lt;p&gt;There isn't much to this step. We're simply going to add a file named &lt;code&gt;app-config.json&lt;/code&gt; and populate it with the following JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "api": "http://localhost:5000/"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Ensuring the config file is copied to the &lt;code&gt;dist&lt;/code&gt; folder
&lt;/h3&gt;

&lt;p&gt;To achieve this, we need to make an addition to the webpack configuration in the &lt;code&gt;angular.json&lt;/code&gt; file. We need to add the path to our config file to the &lt;code&gt;assets&lt;/code&gt; array in the webpack &lt;code&gt;build&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kjZZzegl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./app-config.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kjZZzegl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./app-config.png" alt="Screenshot - angular.json"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the service
&lt;/h3&gt;

&lt;p&gt;This is a simple service with a private property and two methods - one that sets the property and another that exposes the config data for the rest of your app. We can type the config object with an interface to help ensure we get what we expect from the JSON config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable({
  providedIn: 'root'
})
export class ConfigService {

  private configuration: AppConfig;

  constructor(
    private httpClient: HttpClient
  ) { }

  setConfig(): Promise&amp;lt;AppConfig&amp;gt; {
    return this.httpClient
      .get&amp;lt;AppConfig&amp;gt;('./app-config.json')
      .toPromise()
      .then(config =&amp;gt; this.configuration = config);
  }

  readConfig(): AppConfig {
    return this.configuration;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that the &lt;code&gt;setConfigData&lt;/code&gt; method returns a promise? The initialization of our app will not complete until all promises are resolved so by returning a promise here, we're ensuring that the config data will be available when the rest of our app loads up and needs to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's take a look
&lt;/h2&gt;

&lt;p&gt;With that in place, let's set up the &lt;code&gt;APP_INITIALIZER&lt;/code&gt;. According to the &lt;a href="https://angular.io/api/core/APP_INITIALIZER"&gt;docs&lt;/a&gt;, &lt;code&gt;APP_INITIALIZER&lt;/code&gt; is an injection token that allows us to invoke functions during the bootstrapping process of our application. To do that, we add the &lt;code&gt;ConfigService&lt;/code&gt; and &lt;code&gt;APP_INITIALIZER&lt;/code&gt; token as providers in &lt;code&gt;app.module.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const appInitializerFn = (configService: ConfigService) =&amp;gt; {
  return () =&amp;gt; {
    return configService.setConfig();
  };
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    ConfigService,
    {
      provide: APP_INITIALIZER,
      useFactory: appInitializerFn,
      multi: true,
      deps: [ConfigService]
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that we need to use a factory function to create an instance of our &lt;code&gt;ConfigService&lt;/code&gt; and call the &lt;code&gt;setConfig()&lt;/code&gt; method on it.&lt;/p&gt;

&lt;p&gt;Now, to ensure that this worked as expected, we can inject our &lt;code&gt;ConfigService&lt;/code&gt; into the &lt;code&gt;AppComponent&lt;/code&gt; and call our &lt;code&gt;readConfig()&lt;/code&gt; method to get the config object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  config: AppConfig;

  constructor(private configService: ConfigService) {}

  ngOnInit(): void {
    this.config = this.configService.readConfig();
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In our &lt;code&gt;app.component.html&lt;/code&gt; file, we will just remove all of the default boilerplate HTML and add the followig to display our config data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;{{ config | json }}&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we run our app locally with &lt;code&gt;ng serve&lt;/code&gt;, we will see our JSON configuration object rendered on the webpage. &lt;/p&gt;

&lt;p&gt;To see a working example, take a look at the &lt;a href="https://gitlab.com/kylerjohnsondev/ng-runtime-config"&gt;GitLab Repo&lt;/a&gt;.&lt;/p&gt;

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