<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Adrian Faciu's Blog RSS Feed]]></title><description><![CDATA[My personal website]]></description><link>https://adrianfaciu.dev</link><generator>GatsbyJS</generator><lastBuildDate>Wed, 27 May 2026 21:53:41 GMT</lastBuildDate><item><title><![CDATA[Exploring template literal types in TypeScript]]></title><description><![CDATA[Follow me along as I explore two new features of TypeScript 4.1, template literal types and recursive conditional types. All this to create a typed version of a function that reads data from an API.]]></description><link>https://adrianfaciu.dev/posts/template-literal-types/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/template-literal-types/</guid><pubDate>Tue, 25 Jan 2022 13:00:37 GMT</pubDate><content:encoded>&lt;p&gt;This post will explore my train of thought following a question about &lt;strong&gt;how I would type an existing function&lt;/strong&gt;. This code was not used in any production app, but it was a good exercise in working with TypeScript while trying to solve this particular problem.&lt;/p&gt;
&lt;p&gt;We will go a bit deeper by using (recursive) conditional types, template literal types, index accessed types, and a suite of other helper types.
Previous knowledge of &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; is required in order to be able to follow along. Knowing about these types beforehand will also help, but I’ll try to provide links and examples for further reading.&lt;/p&gt;
&lt;p&gt;So grab your favorite hot beverage and get ready for a post that goes towards the ‘heavy to read’ end of the spectrum.
Experimenting with the code as we go along is encouraged, for example in the &lt;a href=&quot;https://www.typescriptlang.org/play&quot;&gt;TypeScript playground&lt;/a&gt;. There is also a link with the solution at the end.&lt;/p&gt;
&lt;h1 id=&quot;the-problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The problem&lt;/h1&gt;
&lt;p&gt;Let’s assume we have an existing code base, with a general function that reads data from an API. We can pass it the property names that we want to read for that specific object type, and the URL. Might look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Assuming we have a &lt;code class=&quot;language-text&quot;&gt;Car&lt;/code&gt; object:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  price&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use our function to fetch a list of available cars, and what properties we need for each:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id, name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We are specifying that we want the list of cars, but only the &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt; properties on them. In our simple example, this is somehow irrelevant. But if you are working with complex objects or large volume of data, this can save a lot of bandwidth and improve the speed of our applications. If we have a large list of complex objects, including just a few properties (vs. all) would make a big difference.&lt;/p&gt;
&lt;p&gt;Another possible use case is if you have different clients (web, mobile) that use the same APIs, but they display different data. So this might be useful to fetch what’s needed in each case. There are different ways to implement this on the backend, depending on what technology you are using.&lt;/p&gt;
&lt;p&gt;Going back to our function, we can think about this as being used inside an existing code base. Our task at hand would be to create a proper typed version of &lt;code class=&quot;language-text&quot;&gt;fetchData&lt;/code&gt;, so that it will be easier to use and make our code better.&lt;/p&gt;
&lt;h1 id=&quot;return-type&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#return-type&quot; aria-label=&quot;return type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#return-type&quot; aria-label=&quot;return type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Return type&lt;/h1&gt;
&lt;p&gt;This should be straight forward. We want to get a specific type back, so we make the function generic, and specify ourselves what the return type is:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can use it as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cars &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now TypeScript will make sure our &lt;code class=&quot;language-text&quot;&gt;cars&lt;/code&gt; variable has the proper type. It’s a bit tricky that we have to explicitly write this, but there is no easy way out of it. We cannot easily map the type to a string, so this is what we have to settle with. All the popular data fetching libraries have an implementation similar to this.&lt;/p&gt;
&lt;p&gt;If we want to make sure developers working in this codebase use the correct type, we could encapsulate this at the API layer in one way or another. For example creating a &lt;code class=&quot;language-text&quot;&gt;fetchCars&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchCars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This takes care of the basics, now let’s see about that &lt;code class=&quot;language-text&quot;&gt;properties&lt;/code&gt; type.&lt;/p&gt;
&lt;h1 id=&quot;one-property&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#one-property&quot; aria-label=&quot;one property permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#one-property&quot; aria-label=&quot;one property permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;One property&lt;/h1&gt;
&lt;p&gt;It would be nice to be able to specify only existing properties of a &lt;code class=&quot;language-text&quot;&gt;Car&lt;/code&gt; when we call this! In that way, we’re sure our function is typed.&lt;/p&gt;
&lt;p&gt;First thing I would think of is &lt;code class=&quot;language-text&quot;&gt;keyof&lt;/code&gt;. This will allow us to get all the keys of a specified type. So if we have something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarKeys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will expand into:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarKeys&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This happens because those are all the properties that we defined on our &lt;code class=&quot;language-text&quot;&gt;Car&lt;/code&gt; type above. Any time we add or remove one from the Car type, the &lt;code class=&quot;language-text&quot;&gt;keyof&lt;/code&gt; derived type will be updated. You can see the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/keyof-types.html&quot;&gt;official docs&lt;/a&gt; for more.&lt;/p&gt;
&lt;p&gt;So we update our function to fetch data with this knowledge:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This works, we can make calls and get back data with what property we want:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ✅&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But we can specify &lt;strong&gt;only one property&lt;/strong&gt; at a time, which is not exactly what we want 😅:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Argument of type &apos;&quot;name, id&quot;&apos; is not assignable to parameter of type...&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id, name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But before we are going to look at how to implement support for multiple properties, we need to get ourselves conformable with some (new) TypeScript features.&lt;/p&gt;
&lt;h1 id=&quot;template-literal-and-recursive-conditional-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#template-literal-and-recursive-conditional-types&quot; aria-label=&quot;template literal and recursive conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#template-literal-and-recursive-conditional-types&quot; aria-label=&quot;template literal and recursive conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Template literal and recursive conditional types&lt;/h1&gt;
&lt;p&gt;A possible solution to our problem is the use of &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#template-literal-types&quot;&gt;template literal types&lt;/a&gt; and &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#recursive-conditional-types&quot;&gt;recursive conditional types&lt;/a&gt;, introduced in TypeScript 4.1. You can see the release notes for full details, but I’ll try to show some examples so we can better understand them.&lt;/p&gt;
&lt;h3 id=&quot;template-literal-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#template-literal-types&quot; aria-label=&quot;template literal types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#template-literal-types&quot; aria-label=&quot;template literal types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Template literal types&lt;/h3&gt;
&lt;p&gt;Using similar concepts from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;template literals&lt;/a&gt;, we create a type using substitutions:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Programming&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;programming&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Statement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;love &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Programming&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &apos;love programming&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is pretty straight forward, but we can explore one additional trick:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Programming&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;programming&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reading&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;reading&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Statement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;love &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Programming &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Reading&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What happens if we use a union operator with a template literal type? &lt;em&gt;It will create all the possible combinations!&lt;/em&gt; So this will get expanded to:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Statement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;love programming&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;love reading&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use something a bit more complex as an example to better grasp it. Lets compose some CSS properties:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CssProperty&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;margin&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;padding&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PropertySide&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;top&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;right&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bottom&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Prop&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;CssProperty&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;PropertySide&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which will get expanded to all possible combinations:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Prop&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;margin-top&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;margin-right&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;margin-bottom&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;margin-left&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;padding-top&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;padding-right&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;padding-bottom&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;padding-left&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;conditional-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conditional-types&quot; aria-label=&quot;conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#conditional-types&quot; aria-label=&quot;conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conditional types&lt;/h3&gt;
&lt;p&gt;Since &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html&quot;&gt;TypeScript 2.8&lt;/a&gt; we have &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/conditional-types.html&quot;&gt;conditional types&lt;/a&gt; at our disposal. Let’s explore them a bit.&lt;/p&gt;
&lt;p&gt;A simple example of this would be (re)creating the &lt;code class=&quot;language-text&quot;&gt;NonNullable&lt;/code&gt; type. This will remove &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;undefined&lt;/code&gt; from types:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NonNullable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;never&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As the name implies, you can think of conditional types like an &lt;code class=&quot;language-text&quot;&gt;if&lt;/code&gt; statement. If the condition is true, resolve to the first type, if not, the second one. If the expression is not that familiar, you can have a quick look at the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator&quot;&gt;conditional operator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the example above, we check to see if the generic type matches null or undefined and:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if true -&gt; we return &lt;code class=&quot;language-text&quot;&gt;never&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if false -&gt; we return the generic type itself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In TypeScript, &lt;code class=&quot;language-text&quot;&gt;never&lt;/code&gt; is a built-in type representing values that are &lt;em&gt;never&lt;/em&gt; observed. In our case, it removes undefined or null:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// string&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OnlyString&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NonNullable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// number&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OnlyNumber&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NonNullable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;recursive-conditional-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#recursive-conditional-types&quot; aria-label=&quot;recursive conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#recursive-conditional-types&quot; aria-label=&quot;recursive conditional types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Recursive conditional types&lt;/h3&gt;
&lt;p&gt;We had conditional types but, up until &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#recursive-conditional-types&quot;&gt;TypeScript 4.1&lt;/a&gt;, we could not recursively reference the type itself. Let’s try to extract the primitive types from an array, also handling the case when we have deeply nested arrays:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExtractType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;infer&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; ExtractType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As before, we check to see if the generic type matches something like an &lt;code class=&quot;language-text&quot;&gt;Array&lt;/code&gt; and:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if true -&gt; we return the same &lt;code class=&quot;language-text&quot;&gt;ExtractType&lt;/code&gt;, but as a type argument we use the type of the Array itself&lt;/li&gt;
&lt;li&gt;if false -&gt; we return the generic type itself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to figure out what the type of the arrays is, we used the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types&quot;&gt;infer keyword&lt;/a&gt;.
It’s like saying take whatever type you find there, and place it in this &lt;code class=&quot;language-text&quot;&gt;U&lt;/code&gt; variable, so that I can use it later on.&lt;/p&gt;
&lt;p&gt;And we can test it out:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// &apos;string&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; one&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtractType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// &apos;string&apos; | &apos;number&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; two&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtractType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// &apos;string&apos; | &apos;number&apos; | &apos;boolean&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; three&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtractType&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These examples are pretty similar to those from the release notes. Added them here for more context or in case you did not open the links :)&lt;/p&gt;
&lt;p&gt;And now we know everything we need to continue.&lt;/p&gt;
&lt;h1 id=&quot;multiple-properties&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#multiple-properties&quot; aria-label=&quot;multiple properties permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#multiple-properties&quot; aria-label=&quot;multiple properties permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Multiple properties&lt;/h1&gt;
&lt;p&gt;Back to our problem. We have the &lt;code class=&quot;language-text&quot;&gt;Car&lt;/code&gt; type, we used the &lt;code class=&quot;language-text&quot;&gt;keyof&lt;/code&gt; on it, which works, but only with one property at a time, and we would like to expand this to work for all/any combination of them.&lt;/p&gt;
&lt;p&gt;Let’s start the other way around. One solution would be something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Omit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Key&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Key
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;never&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lets go through it step by step. We created a generic type with two arguments: the type of the object we want to use and an union with property names of that type. By default, this will be a union of all the property names, like we’ve seen before. In most cases we’ll use the generic type by passing in only the first argument, as most of the time we want to go through all of the properties, which is what the default, &lt;code class=&quot;language-text&quot;&gt;keyof T&lt;/code&gt;, value does.&lt;/p&gt;
&lt;p&gt;Then, we use a conditional type to see if the second generic argument, the &lt;code class=&quot;language-text&quot;&gt;Key&lt;/code&gt;, looks like a &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt;. This will happen most of the time, for all the properties of our type. When there are no more properties, it will be an empty set, so no string, and we return &lt;code class=&quot;language-text&quot;&gt;never&lt;/code&gt;. This is our way to make sure we don’t get into infinite recursive calls.&lt;/p&gt;
&lt;p&gt;Now, if we still have properties to process, we construct our template literal type: &lt;code class=&quot;language-text&quot;&gt;${Key},${KeysOf&amp;lt;Omit&amp;lt;T, Key&gt;&gt;}&lt;/code&gt;. We want the properties to be separated by a comma, so we add it there. Then we use the same type to create a recursive call.&lt;/p&gt;
&lt;p&gt;The trick here is to use the &lt;a href=&quot;https://mariusschulz.com/blog/the-omit-helper-type-in-typescript&quot;&gt;Omit&lt;/a&gt; helper type. Each time we process a property name, we call the same type recursively, but without the processed property. In this way we handle all the properties one by one, until we call the type with an empty set. In that case, the &lt;code class=&quot;language-text&quot;&gt;Key&lt;/code&gt; will no longer be a string, so we will return never and stop the recursive call.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarWithoutName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Omit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It is equivalent to the initial &lt;code class=&quot;language-text&quot;&gt;Car&lt;/code&gt; type, but without a name:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  price&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last thing to add here is a union with the &lt;code class=&quot;language-text&quot;&gt;Key&lt;/code&gt; itself. This will generate a union with all the possible combinations.&lt;/p&gt;
&lt;p&gt;Then we can update our function with our new type:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;properties&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this will work pretty well. We can specify any combination of properties that we might want to read:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name, price&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;price, name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;price&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id, name, price&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// and so on&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to check this, you can use this yourself (or see the TypeScript playground link at the end):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarProps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will get transformed into:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarProps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name, price&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price, name&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id, name&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id, price&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id, name, price&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id, price,name&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price, id&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name, id&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name, id, price&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name, price,id&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price, id, name&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;price, name, id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are some ways to solve this without using the second generic argument, but I found this way of doing it more straight forward and we get some extra benefits. Notice that we’ve passed only one generic argument so far, but we can also pass the second to explicitly use only specific keys:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or just maybe this way of solving it might have been the easiest for me 😅.&lt;/p&gt;
&lt;h1 id=&quot;complex-nested-objects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#complex-nested-objects&quot; aria-label=&quot;complex nested objects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#complex-nested-objects&quot; aria-label=&quot;complex nested objects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Complex (nested) objects&lt;/h1&gt;
&lt;p&gt;We can further improve on our type. So far we had a simple car, with properties that have primitive values. But in real life, we might have some more complex types. Maybe the car also has an engine:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  power&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  price&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  engine&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Engine&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And, in case of the engine property, we could do the same thing, specify only what properties we want to read from it. Something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetchData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name, engine(power)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/cars&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will mean that we want a list of all the cars, with only the name and engine properties, and on the engine we only need the power property.&lt;/p&gt;
&lt;p&gt;In this part we’ll make use of the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type&quot;&gt;Record&lt;/a&gt; utility type. This helps us check if a type looks like an object, or it is a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Primitive&quot;&gt;primitive type&lt;/a&gt;. Using &lt;code class=&quot;language-text&quot;&gt;Record&lt;/code&gt; we create an object-like type, where the first argument will represent all the properties and the second one the type of those properties. So using something like &lt;code class=&quot;language-text&quot;&gt;Record&amp;lt;string, any&gt;&lt;/code&gt; will create an object that has as properties any &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt; and those can have &lt;code class=&quot;language-text&quot;&gt;any&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;As an alternative, we could have used our own &lt;code class=&quot;language-text&quot;&gt;Primitive&lt;/code&gt; type, or another way to create an object-like type.&lt;/p&gt;
&lt;p&gt;Knowing this, we can build on our previous version to include an additional check:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Omit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Key&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Key
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;never&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have added even another level to our type. After we check that the &lt;code class=&quot;language-text&quot;&gt;Key&lt;/code&gt; is a string, we need to see if the type of that property is a Primitive or not. To get that type, we use the &lt;code class=&quot;language-text&quot;&gt;T[Key]&lt;/code&gt; expression, which is an &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html&quot;&gt;index accessed type&lt;/a&gt;.
Then we do a similar thing, depending on the condition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if it looks like an object, we add round brackets and we do a recursive reference to &lt;code class=&quot;language-text&quot;&gt;KeysOf&lt;/code&gt;, passing in the just extracted index accessed type&lt;/li&gt;
&lt;li&gt;if it’s not an object, we have the previous code, nothing different here&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this solves the problem of a bit more complex types, as we can see if we check it out:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarProps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; KeysOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Car&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will get transformed into an even more complex thing:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CarProps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;price&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;engine(id)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;engine(power)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;engine(id,power)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;engine(power,id)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;price,engine(id)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;price,engine(power)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;price,engine(id,power)&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;68&lt;/span&gt; more &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;price,name,id,engine(power,id)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yes, 68 more options, it indeed has all the possible combinations and we can use any of them to call our function.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;This was an interesting experiment, and it allowed me to play around with template literals and recursive conditional types. They are quite powerful and can provide useful types for our code. This post is a first in a series of “learning in public” style of articles. More will follow :)&lt;/p&gt;
&lt;p&gt;If you want to experiment live with this type, you can use &lt;a href=&quot;https://www.typescriptlang.org/play?#code/C4TwDgpgBAogdgcwJZ2gXigbwLACgpRgD2A7hAE4BcUcArgLYBGFA3HgUgCbUDOw5KBG1wBfYXlCQoAYQCG5KBhz4oXanSat2NWfQi9+g4QTACAxvpoNm5Y1AiIUl+MlTCxeCeGgBpCCB4AeQAzAGUkejAAGwgAHgAVABooPxB7AA9gB04eKABrfyJgqHjFfMLi+IA+MtSMrLgcqD4BRG0AfigAAwASTFSRRL7UoLCI6LjA+iRgBOTUqqqRLqgAHxT-bXUIADctXEloOXIABXIiMB5wyJja-1HridjjqvED7w2AkLnP+uzcgogIolMqA4HVO5pCCZf7NQxtFSdeIAbVSAF0-o1cgAlCBmIjkTixFqCZKyOAgKraAidXr9fwiAAUw3u3xR6KWAEoutSoNQ6QMhvSvsFYlMZj8FksVutUlsaLt9ocZPIzhdchgRt8XsIgA&quot;&gt;this TypeScript playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let me know if you would use something like this in production, or what other interesting ways of solving this problem you have.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Handling Observables in a LitElement component]]></title><description><![CDATA[In this post, we are going to explore how to handle Observables inside a LitElement component. What options we have for this and how I've created a generic solution. It will handle subscribing to a stream, with some extra features and built in functionality.]]></description><link>https://adrianfaciu.dev/posts/observables-litelement/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/observables-litelement/</guid><pubDate>Thu, 06 Aug 2020 20:46:37 GMT</pubDate><content:encoded>&lt;h2 id=&quot;intro&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#intro&quot; aria-label=&quot;intro permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#intro&quot; aria-label=&quot;intro permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Intro&lt;/h2&gt;
&lt;p&gt;Since the first time I’ve used &lt;strong&gt;&lt;a href=&quot;https://rxjs.dev/&quot;&gt;RxJs&lt;/a&gt;&lt;/strong&gt; for some Angular projects, I’ve fallen in love with this library. There are a lot of use cases where it’s applicable. And for me, it makes the whole experience of writing and reading code way better.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lit-element.polymer-project.org/&quot;&gt;LitElement&lt;/a&gt; is a small and lightweight base class for creating web components. It’s easy to use and understand. You can start writing web components without a lot of setup and it’s a joy to use.&lt;/p&gt;
&lt;p&gt;We’re going to have a look at how to use RxJs inside a LitElement web component. Some different approaches we can take to handle and render Observables. Basic knowledge of RxJs, LitElement, and TypeScript is required. If you’re comfortable with any of the big three (React/Angular/Vue) you should be able to follow along.&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#problem&quot; aria-label=&quot;problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#problem&quot; aria-label=&quot;problem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Problem&lt;/h2&gt;
&lt;p&gt;Let’s define a basic LitElement component that we are going to use for our examples:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LitElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; html&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; customElement &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lit-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;p&gt;This is a sample LitElement&amp;lt;/p&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A simple class that extends from LitElement and renders a text. We use the customElement decorator to register the class as a web component.&lt;/p&gt;
&lt;p&gt;Our purpose is to have an Observable and render it inside our component. For a sample stream, we are going to use an interval and take the first ten items from it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; interval &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; take &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs/operators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We generate a new value each second, starting from 0 and we take the first 10. We would like to render this inside our component:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LitElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; html&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; customElement &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lit-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; interval &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; take &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs/operators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;ul&gt;
        &amp;lt;li&gt;Render all items here&amp;lt;/li&gt;
      &amp;lt;/ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Working with Observables inside a LitElement is easy enough, but it involves a bit of code. We need at least to subscribe and schedule an update for anything to show up:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;ul&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          item &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
              &amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;
            &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The connected callback life cycle hook is called when the component is added to the document’s DOM. Here, we want to subscribe to our stream and update the property in our class. Since LitElement is not tracking our &lt;em&gt;data&lt;/em&gt; property, we need to manually request an update each time the value changes.&lt;/p&gt;
&lt;p&gt;In this case, it’s good enough, because our observable will finish after ten items and clean everything up. But what happens if we remove the &lt;strong&gt;take&lt;/strong&gt; method call? We would like to unsubscribe and clean up when our component is removed from the DOM. So we have to add a bit more code to handle that:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  unsubscribe$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;takeUntil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unsubscribe$&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unsubscribe$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unsubscribe$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;ul&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          item &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
              &amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;
            &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To achieve this, we’ve created a &lt;a href=&quot;https://rxjs.dev/api/index/class/Subject&quot;&gt;Subject&lt;/a&gt;, this is a special type of Observable that also allows us to emit values. We used this inside the disconnected callback to send a new value whenever the life cycle hook is called. Before we subscribe we use the &lt;a href=&quot;https://rxjs.dev/api/operators/takeUntil&quot;&gt;takeUntil&lt;/a&gt; operator to emit the values from the source observable, but only until something is emitted on the unsubscribe stream.&lt;/p&gt;
&lt;p&gt;This is all good and it works, but if we have multiple streams to handle in our component, the amount of code grows a bit with each new one.&lt;/p&gt;
&lt;h2 id=&quot;options&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#options&quot; aria-label=&quot;options permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#options&quot; aria-label=&quot;options permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Options&lt;/h2&gt;
&lt;p&gt;There are a few directions that you can go about if you want to extract this functionality and make it more generic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a simple function&lt;/li&gt;
&lt;li&gt;a directive&lt;/li&gt;
&lt;li&gt;a base class&lt;/li&gt;
&lt;li&gt;a decorator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is also the order in which I’ve explored them. First, we are going to rule out the first two.&lt;/p&gt;
&lt;p&gt;Using a simple function, you cannot monkey patch life cycle hooks of custom elements. This means we cannot extend the functionality of disconnected callback to know when the element was removed and unsubscribe. We cannot clean up after ourselves, so this is not OK.&lt;/p&gt;
&lt;p&gt;While there are a few examples out there with async directives that handle Observables, they have one issue. The directive itself is not aware of the life cycle of the component, so there is no easy way to unsubscribe when needed. The same problem as with a simple function.&lt;/p&gt;
&lt;h2 id=&quot;base-class&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#base-class&quot; aria-label=&quot;base class permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#base-class&quot; aria-label=&quot;base class permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Base class&lt;/h2&gt;
&lt;p&gt;The next option, a base class, is a good, working, option. One advantage is that a lot of projects using LitElement already have a base class, so it’s a matter of extending that one, and having the provided functionality in all the components throughout the app.&lt;/p&gt;
&lt;p&gt;We want to provide a &lt;strong&gt;subscribe&lt;/strong&gt; method, that could be used inside a component to subscribe to an Observable and request an update whenever new data comes in. Something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values$&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We start with something simple, the base class and a simple implementation for the subscribe method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RxLitElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;propertyName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;propertyName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get the stream and the property name where we want to place the values. We subscribe to the stream, update the class property with new values, and request an update so that our UI will reflect the new data.&lt;/p&gt;
&lt;p&gt;Then we can update our component and use our new base class:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-element&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RxLitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values$&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;ul&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          item &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
              &amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;
            &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run this, you will see that nothing happens. This is because we expect that &lt;em&gt;data&lt;/em&gt; is an array and in this case, it’s only a value. We can slightly update our stream to transform it into an array with all the values so far. We’ll use &lt;a href=&quot;https://rxjs.dev/api/operators/scan&quot;&gt;scan&lt;/a&gt; operator to transform it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;values$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The scan operator is similar to reduce, but it emits each intermediate result. We start with an empty array, for each value we append it to the array and emit the result. Now everything works as before, and all the code that handles the subscribe is abstracted in our base class.&lt;/p&gt;
&lt;p&gt;As a possible future improvement, we could pass in a function to our subscribe method. This will handle the update of the property and will allow custom functionality, like adding items to an array, properties to an object, and so on.&lt;/p&gt;
&lt;h2 id=&quot;type-safety&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#type-safety&quot; aria-label=&quot;type safety permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#type-safety&quot; aria-label=&quot;type safety permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Type safety&lt;/h2&gt;
&lt;p&gt;The first thing that we want to improve is the typing, we want to make sure we send in an Observable and a property name that exists in our class:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;    &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      propKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stream$&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using &lt;code class=&quot;language-text&quot;&gt;keyof this&lt;/code&gt; we create a subtype of string that can have as values only the property names defined in our class. If we have an interface with some properties:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  age&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  location&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;K1&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; Person&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;name&quot; | &quot;age&quot; | &quot;location&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We defined our method with a generic Key type parameter that extends from this sub type &lt;code class=&quot;language-text&quot;&gt;Key&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;extends&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;keyof&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;this&lt;/code&gt;. In this way, we make sure we can pass in only properties that exist in our class.&lt;/p&gt;
&lt;p&gt;Next, we can define the stream as an Observable, but we need a type for that. We have to use lookup types, to make sure that the type of the values emitted by the Observable is the same as the type of the property that will receive them:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  age&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  location&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;P1&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Person&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// string&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using lookup types, we can take the defined type of our property, and make an Observable of that specific type.&lt;/p&gt;
&lt;p&gt;Now our method is type-safe and it prevents us from making mistakes when using it.
You can read more about keyof and lookup types &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;unsubscribe&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unsubscribe&quot; aria-label=&quot;unsubscribe permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#unsubscribe&quot; aria-label=&quot;unsubscribe permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unsubscribe&lt;/h2&gt;
&lt;p&gt;The first improvement is to unsubscribe from the Observable when our component is removed from the DOM. For that, we can use the &lt;strong&gt;&lt;a href=&quot;https://rxjs.dev/api/operators/takeUntil&quot;&gt;takeUntil&lt;/a&gt;&lt;/strong&gt; operator.&lt;/p&gt;
&lt;p&gt;To use this we create a &lt;a href=&quot;https://rxjs.dev/api/index/class/Subject&quot;&gt;Subject&lt;/a&gt;, that will emit a value when the component disconnected callback is called. Then we’ll use it before we subscribe to our stream:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; unsubscribe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;unsubscribe&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RxLitElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;unsubscribe&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    propKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    stream$&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;takeUntil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;unsubscribe&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;propertyName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;unsubscribe&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;unsubscribe&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We used a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol&quot;&gt;symbol&lt;/a&gt; to define the unsubscribe subject to make sure it’s unique, so it does not clash with other user-defined properties, and that by default it’s not accessible from outside our base class.&lt;/p&gt;
&lt;p&gt;This is the basic working implementation, but we can add some more features that will help us when using this approach.&lt;/p&gt;
&lt;h2 id=&quot;extra-features-for-our-base-class&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#extra-features-for-our-base-class&quot; aria-label=&quot;extra features for our base class permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#extra-features-for-our-base-class&quot; aria-label=&quot;extra features for our base class permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Extra features for our base class&lt;/h2&gt;
&lt;p&gt;For safe programming practices, we can check that the stream we get inside our subscribe method is indeed an Observable. We get all the type checking at runtime. RxJs has a method called &lt;a href=&quot;https://rxjs.dev/api/index/function/isObservable&quot;&gt;isObservable&lt;/a&gt; that we can take advantage of:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isObservable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stream$&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Invalid Observable!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we want to be extra safe, we can even check the property:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;propKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Invalid property name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now to some more useful features, we might want to call the subscribe method several times in our component life cycle, for the same property, with different streams. We want to handle this, meaning unsubscribe from the old observable before subscribing to the new one. And ignoring subscribe calls for the same property and the same Observable.&lt;/p&gt;
&lt;p&gt;For this, we need to remember the subscriptions and the stream that was used to create them. What we want to get a hold of:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExistingSubscription&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  stream$&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  subscription&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Subscription&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can create a map with all this information:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; subscriptions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;subscriptions&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;subscriptions&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExistingSubscription&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And work with it inside our subscribe method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Key &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    propKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    stream$&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existingSubscription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;subscriptions&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;propKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingSubscription&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingSubscription&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;stream$ &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; stream$&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; existingSubscription&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;subscription&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unsubscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; subscription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stream$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;subscriptions&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;propKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stream$&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subscription &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We check to see if we already have a subscription for that property name. If yes, in case it’s the same stream, we ignore the call, no need to do anything. If it’s a different stream, we unsubscribe from the old one before handling it. In the end, we store the new subscription and stream combination using the property name as a key.&lt;/p&gt;
&lt;p&gt;This is a more complete implementation of our base class, which besides extracting all this functionality in a central place, provides us with a few advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;type safety (we can use only existing property names and Observable objects)&lt;/li&gt;
&lt;li&gt;unsubscribes when the component is removed&lt;/li&gt;
&lt;li&gt;unsubscribes from old observable if called again on the same property with a different Observable&lt;/li&gt;
&lt;li&gt;ignores calls on the same property with the same Observable&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;decorator&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#decorator&quot; aria-label=&quot;decorator permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#decorator&quot; aria-label=&quot;decorator permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decorator&lt;/h2&gt;
&lt;p&gt;Now, how about that subscribe call, could we improve it a bit more? Like avoid calling it inside our connected callback manually for each property? It turns out we can! In some specific cases, like when the Observable we want to subscribe to is not a member of our class, we could improve things a bit further.&lt;/p&gt;
&lt;p&gt;That is, by creating a decorator that will do this for us. Decorators are an experimental feature, but they are useful in certain situations.&lt;/p&gt;
&lt;p&gt;A decorator is a special kind of function that can be attached to classes, methods, properties, or arguments. They are used in the form of &lt;code class=&quot;language-text&quot;&gt;@expression&lt;/code&gt; where expression is the name of the function. In our case we use subscribe:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;subscribe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stream&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RxLitElement&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  targetPrototype&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  propertyKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;keyof&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;K&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Invalid stream!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; initial &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; targetPrototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connectedCallback&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  targetPrototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;connectedCallback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    initial&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;propertyKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we want to customize how the decorator is applied to our property we created a decorator factory. That is a function that returns another function. A decorator for a property is always a function that gets the prototype and the property key, but we also want to pass in a stream for each use.&lt;/p&gt;
&lt;p&gt;Inside the function, we monkey patch the connected callback method of our class and call the subscribe method inside it. Pretty much what we manually did before.&lt;/p&gt;
&lt;p&gt;And we can use it for our components to simplify code even further:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DemoElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RxLitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  streamValues&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The limitation on what streams we can use here comes from the way decorators work. We don’t have access to the class instance at the moment when the decorator is parsed, so there is no way to access the instance variables there. Hence the limitation.&lt;/p&gt;
&lt;p&gt;You can find more information about how to &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/decorators.html&quot;&gt;create decorators here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-end&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-end&quot; aria-label=&quot;the end permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#the-end&quot; aria-label=&quot;the end permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The end&lt;/h2&gt;
&lt;p&gt;To help with this, I’ve extracted the functionality into &lt;a href=&quot;https://www.npmjs.com/package/rx-lit&quot;&gt;a small lib&lt;/a&gt;. Or even better, you can fetch the code from &lt;a href=&quot;https://github.com/adrianfaciu/rx-lit&quot;&gt;GitHub&lt;/a&gt; and use it in your project, if you find it useful.&lt;/p&gt;
&lt;p&gt;If you know other solutions to this problem or have a different idea, feel free to let me know. Or why not, open a pull request 🙂.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Typed fake REST APIs]]></title><description><![CDATA[See how to create a fake REST API using JSON Server. TypeScript will protect us against any model changes and faker.js will help with generating random data. Use it for local development, testing or any other related activities.]]></description><link>https://adrianfaciu.dev/posts/Typed-fake-REST-APIs/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/Typed-fake-REST-APIs/</guid><pubDate>Mon, 30 Mar 2020 13:00:37 GMT</pubDate><content:encoded>&lt;p&gt;Whenever you start working on a new project, you might need to consume an API. But that API might not be written yet, or you don’t want to hit the real thing while developing the app.&lt;/p&gt;
&lt;p&gt;In this post we’re going to have a look at using &lt;a href=&quot;https://github.com/typicode/json-server&quot;&gt;JSON Server&lt;/a&gt; and &lt;a href=&quot;https://github.com/Marak/Faker.js#readme&quot;&gt;faker.js&lt;/a&gt; to create a fake REST API. You can use it for local development, testing or any other related tasks.&lt;/p&gt;
&lt;p&gt;Basic knowledge of &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; is required to follow along.
Out of habit and personal preference, I’ll use &lt;a href=&quot;https://yarnpkg.com/&quot;&gt;yarn&lt;/a&gt; instead of npm for all the examples.&lt;/p&gt;
&lt;h1 id=&quot;setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setup&quot; aria-label=&quot;setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#setup&quot; aria-label=&quot;setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup&lt;/h1&gt;
&lt;p&gt;We’re going to assume you already have a TypeScript project where you want to add and use the fake API. If you do, skip to the next section. If not, and you want to follow along with the code, let’s create a simple project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; fake-rest-api &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; fake-rest-api
&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; init&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hit enter at any of the inputs to use the defaults, as long as you don’t want to fill in something more useful 🙂.&lt;/p&gt;
&lt;p&gt;Install the latest version of TypeScript and generate a new config file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; typescript &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; tsc &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only thing we want to change in the config file is the &lt;em&gt;outDir&lt;/em&gt; property, we can set it to &lt;em&gt;dist.&lt;/em&gt; By default, TypeScript will place the output in the same place as the input files. We want things to be a bit cleaner, hence using an output folder.&lt;/p&gt;
&lt;h1 id=&quot;json-server&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#json-server&quot; aria-label=&quot;json server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#json-server&quot; aria-label=&quot;json server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;JSON Server&lt;/h1&gt;
&lt;p&gt;Let’s get started and create our fake API. First, install JSON Server:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; json-server &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Usually, the server will use JSON files with our data. In our case, we’re going to use TypeScript, because we want to add a bit of type safety to our fake API. Whenever our types change we want to know and make the appropriate changes in the fake data.&lt;/p&gt;
&lt;p&gt;Create a new file &lt;em&gt;server.ts&lt;/em&gt;, inside a &lt;em&gt;src&lt;/em&gt; folder, and add this code to get it up and running:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Hello from our fake API&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The convention is to export a function that returns an object which is the structure of the fake API. The properties of the object are the routes and the values are the data.&lt;/p&gt;
&lt;p&gt;Now we want to run the server with this file, but before we can do that we also have to compile it to plain JavaScript. Let’s create a script to do that. Add the following to &lt;em&gt;package.json&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;scripts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;fake-api&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsc &amp;amp;&amp;amp; json-server dist/server.js&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It would be great if we could run both these commands with the &lt;em&gt;watch&lt;/em&gt; flag, which they do support. This would restart the server each time we make a change. Unfortunately, last time I’ve checked, the watch mode for JSON Server was working only with JSON files. So don’t forget to manually restart the server after you make some changes to the data.&lt;/p&gt;
&lt;p&gt;If you add this to an existing project, you can have a TypeScript configuration file only for this fake API, and you could compile it with a command like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;tsc &lt;span class=&quot;token parameter variable&quot;&gt;--project&lt;/span&gt; ./mock-server/tsconfig.mock-server.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will allow you to set some project-specific settings, like a different output folder.&lt;/p&gt;
&lt;h1 id=&quot;built-in-features&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#built-in-features&quot; aria-label=&quot;built in features permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#built-in-features&quot; aria-label=&quot;built in features permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Built-in features&lt;/h1&gt;
&lt;p&gt;JSON Server has some great built-in features that you should be aware of. Among them, two are quite important in our case.&lt;/p&gt;
&lt;p&gt;If you make any POST, PUT, PATCH or DELETE requests your data will be affected. You need to be aware of this when testing.&lt;/p&gt;
&lt;p&gt;There are some built-in routes. For example, if you have a collection of items and each item has an id, you get individual access to each item without any other configuration. If the base path is &lt;code class=&quot;language-text&quot;&gt;*/items*&lt;/code&gt;, you can go to &lt;code class=&quot;language-text&quot;&gt;*/items/123*&lt;/code&gt;, and get the item that has an id equal to 123. This will greatly simplify your routing config. You also have built-in filter, pagination, and sort.&lt;/p&gt;
&lt;h1 id=&quot;custom-routes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#custom-routes&quot; aria-label=&quot;custom routes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#custom-routes&quot; aria-label=&quot;custom routes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Custom routes&lt;/h1&gt;
&lt;p&gt;Sometimes we might want to use some custom routes. Maybe we want to simplify what a route looks like or redirect to the same data without changing the file we use to generate out API from.&lt;/p&gt;
&lt;p&gt;To do that we can add a file named &lt;em&gt;routes.json&lt;/em&gt; to our project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;/foo/bar/baz&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/test&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example we have a resource located at &lt;code class=&quot;language-text&quot;&gt;*/foo/bar/baz*&lt;/code&gt;, which should return the same data as &lt;code class=&quot;language-text&quot;&gt;*/test*&lt;/code&gt;. But we don’t want to create a deeply nested structure within our config object, so we use the routes file to redirect to test.&lt;/p&gt;
&lt;p&gt;Also need to update the command used to start the server for this to work:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;fake-api&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsc &amp;amp;&amp;amp; json-server dist/server.js --routes src/routes.json&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go to &lt;code class=&quot;language-text&quot;&gt;*foo/bar/baz*&lt;/code&gt; and notice we get the same result as for &lt;code class=&quot;language-text&quot;&gt;*/test*&lt;/code&gt;, but the URL will remain the same.&lt;/p&gt;
&lt;p&gt;JSON Server is packed with features and offers way more. We’ve just scratched the surface a bit here. See the &lt;a href=&quot;https://github.com/typicode/json-server&quot;&gt;official documentation&lt;/a&gt; for more information about what you can do with it.&lt;/p&gt;
&lt;h1 id=&quot;typed-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#typed-data&quot; aria-label=&quot;typed data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#typed-data&quot; aria-label=&quot;typed data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Typed data&lt;/h1&gt;
&lt;p&gt;All good and nice, but so far we did not take advantage of TypeScript almost at all. Let’s assume we have an &lt;em&gt;Item&lt;/em&gt; interface that looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go ahead and add this as &lt;em&gt;item.ts&lt;/em&gt; to the project, if you did not do it already. This is an example of a type of data that we can get from a real API. Inside a data folder we can create an items file with some test data:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../types/item&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;foo&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bar&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;baz&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each time a property is added, renamed or any other relevant change is made to the type, we’ll know right away, when compiling our server, and we’ll be able to easily update the data.&lt;/p&gt;
&lt;p&gt;I’ve used a similar approach, but without TypeScript and believe me, it was no fun 🙂.&lt;/p&gt;
&lt;p&gt;After we add the items object to our server file, we’ll have the new endpoint available:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./data/items&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function-variable function&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Hello from our fake API&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we have all the fake data inside a folder within TypeScript files, we can use this for more purposes. Like unit or integration tests and reference the same files from all our projects where this test data is required.&lt;/p&gt;
&lt;h1 id=&quot;fake-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fake-data&quot; aria-label=&quot;fake data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#fake-data&quot; aria-label=&quot;fake data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fake data&lt;/h1&gt;
&lt;p&gt;When creating fake test data, we can write it manually or do a request to a real API and get some data back. But we might want to use some random fake data to test our application. For this, we’re going to use faker.js.&lt;/p&gt;
&lt;p&gt;Faker.js is a library for generating random data and has a lot of helpful methods for generating addresses, finance information, names, and many other things. Check the &lt;a href=&quot;https://github.com/Marak/Faker.js&quot;&gt;documentation&lt;/a&gt; to find out more.&lt;/p&gt;
&lt;p&gt;We start by installing faker.js along with types:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; faker.js &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; @types/faker &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can use the faker API to generate any kind of data we want. Let’s replace the hardcoded item names with some random ones:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../types/item&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; faker &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;faker&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commerce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;productName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commerce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;productName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commerce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;productName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or better yet, let’s generate a completely random number of items:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../types/item&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; faker &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;faker&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomItems&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; idx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; idx &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; idx&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  randomItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commerce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;productName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; randomItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; randomItems&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without much hassle, we managed to generate fake data for our API.&lt;/p&gt;
&lt;h1 id=&quot;paths-issue&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#paths-issue&quot; aria-label=&quot;paths issue permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#paths-issue&quot; aria-label=&quot;paths issue permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Paths issue&lt;/h1&gt;
&lt;p&gt;I’m a big fan of using absolute paths in a TypeScript project. This allows us to replace imports like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../../../../../types/item&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;with something much nicer:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;types/item&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to read more about this you can google ‘TypeScript paths’ or read my &lt;a href=&quot;https://adrianfaciu.dev/posts/module-imports/&quot;&gt;short article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So if you use this, kudos to you, but you’ll have a small problem. You are required to replace all absolute paths with the relative versions after compiling to JavsScript, for this to work in all environments.&lt;/p&gt;
&lt;p&gt;One of the most used solutions is the &lt;a href=&quot;https://github.com/dividab/tsconfig-paths&quot;&gt;tsconfig-paths&lt;/a&gt; package. As usual, we add it using:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; tsconfig-paths &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you have multiple projects in the same workspace and use a different TypeScript config for the fake server you can take that into account. Add this to the server file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; tsConfig &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../tsconfig.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; tsConfigPaths &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tsconfig-paths&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

tsConfigPaths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  baseUrl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dist&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  paths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tsConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compilerOptions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paths&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we load the main config file for the workspace and register the tsconfig-paths package using the paths configured from that one. In our sample project we don’t have this setup, so we don’t add this now.&lt;/p&gt;
&lt;h1 id=&quot;read-only-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#read-only-data&quot; aria-label=&quot;read only data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#read-only-data&quot; aria-label=&quot;read only data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Read-only data&lt;/h1&gt;
&lt;p&gt;As discussed above, one of the features of JSON server is that it saves any operations we make on our API. So if we make a POST/PUT request the values will be updated.&lt;/p&gt;
&lt;p&gt;In some cases, we might not want this and we could use middleware to handle only GET requests. We can create a new file called &lt;em&gt;readonly-middleware.ts&lt;/em&gt; in our project and using an express like syntax, handle only these requests:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleOnlyGet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handleOnlyGet&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For any request that is not a GET return a 200 OK status and don’t do anything. We need to add this to the script used to start the server:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;fake-api&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsc &amp;amp;&amp;amp; json-server dist/server.js --routes src/routes.json --middlewares dist/readonly-middleware.js&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;end&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#end&quot; aria-label=&quot;end permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#end&quot; aria-label=&quot;end permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;End&lt;/h1&gt;
&lt;p&gt;Hopefully, you’ve found this useful, and you’ll be able to use it in your projects. The code can be found on &lt;a href=&quot;https://github.com/adrianfaciu/typed-fake-api&quot;&gt;GitHub&lt;/a&gt;. In a future post we’ll experiment with using &lt;a href=&quot;https://github.com/json-schema-faker/json-schema-faker&quot;&gt;JSON Schema Faker&lt;/a&gt; to achieve a similar result. Keep hacking!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Custom Angular directives]]></title><description><![CDATA[In this post, we are going to talk about one of the most important building blocks of an Angular application. As we know, an application is like a tree of components. And these components are actually directives with a template. We’ll focus on Angular directives, both attribute and structural.]]></description><link>https://adrianfaciu.dev/posts/aggrid-angular-directives/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/aggrid-angular-directives/</guid><pubDate>Fri, 19 Jul 2019 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;This is a post written for &lt;a href=&quot;https://www.ag-grid.com/&quot;&gt;AgGrid&lt;/a&gt;, you can see the &lt;a href=&quot;https://blog.ag-grid.com/custom-angular-directives/&quot;&gt;original here.&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;intro&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#intro&quot; aria-label=&quot;intro permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#intro&quot; aria-label=&quot;intro permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Intro&lt;/h1&gt;
&lt;p&gt;In this post, we are going to talk about one of the most important building blocks of an &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; application. As we know, an application is like a tree of components. And these components are actually directives with a template.&lt;/p&gt;
&lt;p&gt;We’ll focus on Angular directives, both attribute and structural. And we’ll talk a bit about components. What they are and how can we create custom ones. Some basic knowledge of &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; and &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt; is required to follow along.&lt;/p&gt;
&lt;h1 id=&quot;overview&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#overview&quot; aria-label=&quot;overview permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#overview&quot; aria-label=&quot;overview permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Overview&lt;/h1&gt;
&lt;p&gt;Directives allow us to extend or manipulate the DOM. Angular components, which as we said, are directives with a template, allow us to extend the DOM by creating custom components along with the native ones like &lt;em&gt;button&lt;/em&gt; or &lt;em&gt;div&lt;/em&gt;. We know they are similar to directives because internally they use the directive API.&lt;/p&gt;
&lt;p&gt;Directives can be split into two categories: &lt;strong&gt;attribute&lt;/strong&gt; and &lt;strong&gt;structural&lt;/strong&gt;. As the name suggests, attribute directives will be able to change the characteristics of a single element. While the structural ones are able to add or remove blocks of elements.&lt;/p&gt;
&lt;p&gt;Some examples of structural directives are &lt;a href=&quot;https://angular.io/api/common/NgIf&quot;&gt;NgIf&lt;/a&gt;, used to add/remove an element from the DOM based on a condition:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;*ngIf&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;condition&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This shows up only if the condition is true&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And &lt;a href=&quot;https://angular.io/api/common/NgForOf&quot;&gt;NgForOf&lt;/a&gt;, used to iterate over a collection and render a template for each item:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;*ngFor&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;let item of items&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ item.text }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As for attribute directives, &lt;a href=&quot;https://angular.io/api/common/NgClass&quot;&gt;NgClass&lt;/a&gt; is the first that comes to mind. It is used to dynamically add/remove CSS classes associated with an element:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[ngClass]&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;[&apos;first&apos;, &apos;second&apos;]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;...&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To declare a directive, we must use the &lt;a href=&quot;https://angular.io/api/core/Directive&quot;&gt;@Directive&lt;/a&gt; decorator. This will mark that specific class as an Angular directive.&lt;/p&gt;
&lt;h1 id=&quot;selectors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#selectors&quot; aria-label=&quot;selectors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#selectors&quot; aria-label=&quot;selectors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Selectors&lt;/h1&gt;
&lt;p&gt;The minimum thing we need to pass to the Directive decorator is the &lt;a href=&quot;https://angular.io/api/core/Directive#selector&quot;&gt;selector&lt;/a&gt; property:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[foo]&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FooDirective&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors&quot;&gt;CSS selector&lt;/a&gt; that will identify the directive inside a template. It will allow Angular to create an instance of the directive whenever needed. These CSS selectors are &lt;em&gt;quite powerful&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A most common scenario is to target attributes of an element &lt;code class=&quot;language-text&quot;&gt;[foo]&lt;/code&gt;. The brackets ([]) mark it as an attribute selector. Meaning it will look at all the elements in the template that have an attribute called foo. We could also limit this to specific elements by extending the selector: &lt;code class=&quot;language-text&quot;&gt;div[foo]&lt;/code&gt;. This will locate all the &lt;em&gt;div&lt;/em&gt; elements that have an attribute named foo.&lt;/p&gt;
&lt;p&gt;Playing around with this we could select all elements of a specific type, an element with a specific class or even using pseudo-classes like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:not&quot;&gt;:not&lt;/a&gt;. However, you should keep in mind that it does not support nesting selectors.&lt;/p&gt;
&lt;p&gt;For most cases, a selector for a specific attribute is what we need, but we can also get pretty wild with them.&lt;/p&gt;
&lt;h1 id=&quot;export&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#export&quot; aria-label=&quot;export permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#export&quot; aria-label=&quot;export permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Export&lt;/h1&gt;
&lt;p&gt;Another important property for a directive is &lt;a href=&quot;https://angular.io/api/core/Directive#exportAs&quot;&gt;exportAs&lt;/a&gt;. This defines a name that can be used to fetch an instance of our directive in our template.
For example in our custom directive:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[foo]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  exportAs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;appFoo&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FooDirective&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ve added a value for &lt;strong&gt;exportAs&lt;/strong&gt; and now we could use it in a template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[foo]&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;#dirInstance&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;appFoo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This comes in handy when we want to show certain values of the directive, call methods on it, or pass it as a reference to some other method. For a more practical example, suppose we have an input and we want to send the text to a function call from the template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;#myInput&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;(click)&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;performAction(myInput.value)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are a few other properties that we can set for a directive, the above two being just some examples. You can see all of them in the very good &lt;a href=&quot;https://angular.io/api/core/Directive&quot;&gt;Angular documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;custom-attribute-directive&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#custom-attribute-directive&quot; aria-label=&quot;custom attribute directive permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#custom-attribute-directive&quot; aria-label=&quot;custom attribute directive permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Custom attribute directive&lt;/h1&gt;
&lt;p&gt;Now to some more real-world examples. We’ll start with a simple attribute directive that will set the focus to an element whenever it’s displayed on the screen.&lt;/p&gt;
&lt;p&gt;We start with the basics and create the directive class:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;appFocus&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppFocus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adding the attribute that matches the selector to an element will tell Angular to create an instance of the directive and attach it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;appFocus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To get an instance of the element that the directive is attached to, we can use Angular dependency injection mechanism. Adding a reference to &lt;a href=&quot;https://angular.io/api/core/ElementRef&quot;&gt;ElementRef&lt;/a&gt;, in the constructor will get us access to what we need:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; elementRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ElementRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have access to the element and bring focus to it when needed. We can implement the &lt;a href=&quot;https://angular.io/api/core/OnInit&quot;&gt;OnInit&lt;/a&gt; lifecycle hook and focus the element there:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;appFocus&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppFocus&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OnInit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; elementRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ElementRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elementRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nativeElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will work, but there are a few things we can improve.&lt;/p&gt;
&lt;p&gt;We might want to disable this functionality dynamically sometimes. So we can add an input to our directive to control this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Input&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; appFocus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice how we used the same name for the input as the selector. This a common practice and will simplify usage:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[appFocus]&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;shouldFocus&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have to check when the appFocus input will get a new value, and if it’s true, focus the element. We can achieve this using the &lt;a href=&quot;https://angular.io/api/core/OnChanges&quot;&gt;OnChanges&lt;/a&gt; lifecycle hook:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ngOnChanges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;changes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SimpleChanges&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;changes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appFocus&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elementRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nativeElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A better real world example would be to place the directive on an element without any property binding:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;appFocus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This adds a subtle problem. The value for our input becomes an empty string and this will evaluate to false. So our directive will no longer work. We have to update the if condition to properly transform a string value to boolean. This is called coercion, and if we’re using &lt;a href=&quot;https://material.angular.io/cdk/categories&quot;&gt;Component Dev Kit&lt;/a&gt; from Angular Material, we have this utility (coerceBooleanProperty) &lt;a href=&quot;https://github.com/angular/material2/blob/a800c2a68014c77d0f29b5229a1938bed050813a/src/cdk/coercion/boolean-property.ts&quot;&gt;built in&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lastly, we can see that we’re using the &lt;strong&gt;nativeElement&lt;/strong&gt; property to focus. This might be tricky and is not something usually recommended. This will fail in an environment where the DOM is not available and some other custom rendering is used. One way to fix this, is to disable our functionality for such environments.&lt;/p&gt;
&lt;p&gt;One way to achieve this is by using the &lt;a href=&quot;http://isPlatformBrowser&quot;&gt;isPlatformBrowser&lt;/a&gt; function from angular common:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isPlatformBrowser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/common&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function takes as argument a &lt;a href=&quot;https://angular.io/api/core/PLATFORM_ID&quot;&gt;platform ID&lt;/a&gt; that we can also fetch from Angular core:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PLATFORM_ID&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can construct an &lt;em&gt;isBrowser&lt;/em&gt; property and use it in our directive:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; isBrowser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; elementRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ElementRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Inject&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PLATFORM_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; platformId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isBrowser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isPlatformBrowser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;platformId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Applying this inside our ngOnChanges method will fix the problem:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;changes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appFocus &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isBrowser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elementRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nativeElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use this, and our code will only work inside a browser, since we’re using a browser API. Or, as an alternative, we could extend &lt;a href=&quot;https://angular.io/api/core/Renderer2&quot;&gt;Renderer2&lt;/a&gt; and implement the focus method. Using this, we’ll be sure it works on any platform.&lt;/p&gt;
&lt;p&gt;This is a sample on how the directive will work:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.dropbox.com/s/jsnpuhd5dbmp6ne/Focus-Directive.gif?raw=1&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can see all the &lt;a href=&quot;https://stackblitz.com/edit/angular-focus-directive&quot;&gt;code on StackBitz&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;custom-structural-directive&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#custom-structural-directive&quot; aria-label=&quot;custom structural directive permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#custom-structural-directive&quot; aria-label=&quot;custom structural directive permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Custom structural directive&lt;/h1&gt;
&lt;p&gt;Now, to a more complex example, we can have a look at how we could implement a clone of the &lt;a href=&quot;https://angular.io/api/common/NgIf&quot;&gt;NgIf&lt;/a&gt; directive. This will demonstrate how to create a directive that changes the DOM by adding or removing an element.&lt;/p&gt;
&lt;p&gt;We start as before with a class and the directive selector:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[appIf]&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IfDirective&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After we also add it to the app module, we can use it in our template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;appIf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Start editing to see some magic happen :)
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll see later on why we need to make a small change to this.&lt;/p&gt;
&lt;p&gt;Since we want to control when to show and hide the element in a dynamic way we’ll add an Input for this. We use the same name as the directive for ease of use:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[appIf]&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IfDirective&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Input&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; appIf&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the template becomes:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[appIf]&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;show&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Start editing to see some magic happen :)
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In our directive, we can implement the &lt;a href=&quot;https://angular.io/api/core/OnChanges&quot;&gt;OnChanges&lt;/a&gt; lifecycle hook so we can react whenever the input is changed. Now we need to think about how we could add or remove the element.&lt;/p&gt;
&lt;p&gt;For this purpose, Angular provides us with a &lt;a href=&quot;https://angular.io/api/core/ViewContainerRef&quot;&gt;View Container&lt;/a&gt;. This is a special container where one or several views can be attached to a component. If you want to know more about this, go on and read this &lt;a href=&quot;https://blog.angularindepth.com/working-with-dom-in-angular-unexpected-consequences-and-optimization-techniques-682ac09f6866&quot;&gt;great article about working with DOM in Angular&lt;/a&gt;. The views can be created by getting a new instance of a component with &lt;em&gt;createComponent()&lt;/em&gt; or by using a template reference with the &lt;em&gt;createEmbeddedView()&lt;/em&gt; method.&lt;/p&gt;
&lt;p&gt;We’ll use the last one, to create an embedded view from our existing HTML. We first need to import the View Container:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ViewContainerRef &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then inject it in the constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; container&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewContainerRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have an instance of this class in our directive. It represents a container linked to the Html paragraph element from our template. And it allows us to add or remove siblings of this element.&lt;/p&gt;
&lt;p&gt;To be able to add or remove our content whenever we need, we have to make some changes to our directive. Right now it’s attached to the paragraph element, and this one will be rendered right away.&lt;/p&gt;
&lt;p&gt;To tell angular that our directive is a structural one, we can use the &lt;strong&gt;*&lt;/strong&gt; notation. Whenever you see this in front of a directive it means it will manipulate the DOM. So we update our template as so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;*appIf&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;show&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Start editing to see some magic happen :)
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is syntactic sugar, it allows us to write less code. This will actually be transformed to:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ng-template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[appIf]&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;show&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    Start editing to see some magic happen :)
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ng-template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ng-template&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ng-template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can see that everything is wrapped inside an ng-template, and that our directive, which looks like a normal one now, was moved to this new element. Ng-template is an Angular element for displaying content. Similar to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template&quot;&gt;HTML template element&lt;/a&gt;, the content is not rendered right away. Angular will replace it with a debug comment and each directive can do something different with the HTML elements wrapped by this.&lt;/p&gt;
&lt;p&gt;In order to get a reference to this template, we can use the &lt;a href=&quot;https://angular.io/api/core/TemplateRef&quot;&gt;TemplateRef&lt;/a&gt; class. If we import it from &lt;code class=&quot;language-text&quot;&gt;@angular/core&lt;/code&gt; we can add it to the constructor and an instance will be provided to us:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; container&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewContainerRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TemplateRef&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have an instance of the view container, which is bound to a host element where we can add or remove elements. An important point to note here is that the view container reference points to a template element (rendered as HTML comment), not the paragraph. We also have a reference to the template that we want to show or hide. Inside our ngOnChanges method we can update the view as needed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ngOnChanges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appIf&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createEmbeddedView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;template&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All the code is available on &lt;a href=&quot;https://stackblitz.com/edit/angular-ngif-clone&quot;&gt;StackBlitz&lt;/a&gt;. Don’t hesitate to check it out and play with it to better understand the example.&lt;/p&gt;
&lt;p&gt;A nice caveat here is that if you forget to use the * notation to mark the directive as structural, things will not work. You can quickly sort this our from the error message. If you get one saying that it cannot inject a TemplateRef, this is what it’s trying to say. There is no ng-template, so no template to get a reference to.&lt;/p&gt;
&lt;h1 id=&quot;combining-both-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#combining-both-types&quot; aria-label=&quot;combining both types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#combining-both-types&quot; aria-label=&quot;combining both types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Combining both types&lt;/h1&gt;
&lt;p&gt;Now, we’ve seen these two types of directives, we can also use a directive to programmatically add components to our application. For example, we can have an icon component and we want to create a directive that will show or hide it when the element is hovered.&lt;/p&gt;
&lt;p&gt;Let’s create a simple component that shows an icon based on some input string. A simple implementation would be something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;app-icon&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    &amp;lt;i class=&quot;fa&quot; [ngClass]=&quot;iconName&quot;&gt;&amp;lt;/i&gt;
  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppIconComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  iconType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;home&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bars&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;trash&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;close&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;folder&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;folder&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fa-&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;iconType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have all the basic things here. A simple selector, a template and an icon property to hold the type of icon that we want. We make use of the &lt;a href=&quot;https://angular.io/api/common/NgClass&quot;&gt;NgClass&lt;/a&gt; directive to add the desired icon class to the element.&lt;/p&gt;
&lt;p&gt;This is how it would look when used:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;[appIcon]&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;home&apos;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;My Home&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For this, to work, we also need to import font awesome. In the &lt;a href=&quot;https://stackblitz.com/edit/angular-app-icon&quot;&gt;StackBlitz example&lt;/a&gt; I’ve added an import inside the main styles.css file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;@&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As before, we add our component to the declarations array of the application module. But we need to do one more thing here. We also need to add it to the &lt;a href=&quot;https://angular.io/guide/entry-components&quot;&gt;entryComponents array&lt;/a&gt;. This is used for any component that Angular loads dynamically. Which means this component is not used statically in any other static angular component’s template, as in our case. If we omit this, Angular will remove the component from the application bundle, believing that it’s not used. This will, of course, crash our app when we want to programmatically instantiate and add the component.&lt;/p&gt;
&lt;p&gt;We can create our directive, that will look and behave like an attribute directive:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Directive&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[appIcon]&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppIconDirective&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Input&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; appIcon&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;home&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bars&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;trash&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;close&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;folder&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Selector and input with the same name are present.&lt;/p&gt;
&lt;p&gt;The same as for our structural directive, we leverage the View Container to be able to add elements. This is still available even though it’s not a structural directive.&lt;/p&gt;
&lt;p&gt;One last thing we need is to create an instance of our icon component. In Angular, this is done by a so-called component factory, and in order to get an instance of it for our component, we need to make use of a &lt;a href=&quot;https://angular.io/api/core/ComponentFactoryResolver&quot;&gt;component factory resolver&lt;/a&gt;. Our constructor will look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; container&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ViewContainerRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; resolver&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ComponentFactoryResolver&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To create an instance of the component we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;get an instance of our component factory&lt;/li&gt;
&lt;li&gt;create the component and attach it to the view&lt;/li&gt;
&lt;li&gt;set the icon type property on the component&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; factory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resolver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolveComponentFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AppIconComponent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; componentRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
componentRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;iconType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appIcon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, since we want to show this when the host element is hovered we add a &lt;a href=&quot;https://angular.io/api/core/HostListener&quot;&gt;HostListener&lt;/a&gt; for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseenter_event&quot;&gt;mouseenter&lt;/a&gt; event:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HostListener&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;mouseenter&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;showIcon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; factory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resolver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolveComponentFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AppIconComponent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; componentRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  componentRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;iconType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appIcon&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will show the icon, we also need to handle &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseleave_event&quot;&gt;mouseleave&lt;/a&gt; event to hide it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HostListener&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;mouseleave&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;hideIcon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One important thing to remember here, is that the icon element, will be a sibling of the element where the directive is used, and not a child.&lt;/p&gt;
&lt;p&gt;As with the other examples, all the code is &lt;a href=&quot;https://stackblitz.com/edit/angular-app-icon&quot;&gt;available on StackBlitz&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Directives are the building blocks of Angular. Hopefully, now you have a better understanding of what they are and how they work. Let me know what you think and what other interesting ways of using directives you’ve found.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Creating a toast service with Angular CDK]]></title><description><![CDATA[Angular Material is a great material UI design components library for your Angular applications. All the common parts needed to create components, things like layout, accessibility, common components like grid or tree have been isolated inside the CDK.]]></description><link>https://adrianfaciu.dev/posts/angular-toast-service/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/angular-toast-service/</guid><pubDate>Wed, 21 Nov 2018 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://images.unsplash.com/photo-1514464750060-00e6e34c8b8c?ixlib=rb-1.2.1&amp;#x26;ixid=eyJhcHBfaWQiOjEyMDd9&amp;#x26;auto=format&amp;#x26;fit=crop&amp;#x26;w=1267&amp;#x26;q=80&quot; alt=&quot;person holding phone&quot;&gt;&lt;/p&gt;
&lt;p&gt;OK, not that kind of toast message, but something close 😃. Prepare yourself, this will be a long read, starting from scratch up to a full-blown, &lt;em&gt;almost,&lt;/em&gt; &lt;strong&gt;production-ready&lt;/strong&gt; toast service.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://material.angular.io/&quot;&gt;Angular Material&lt;/a&gt; is a great &lt;a href=&quot;https://material.io/&quot;&gt;material UI design&lt;/a&gt; components library for your Angular applications. All the common parts needed to create components, things like layout, accessibility, common components like grid or tree have been isolated inside the &lt;a href=&quot;https://material.angular.io/cdk/categories&quot;&gt;CDK&lt;/a&gt; (Component Development Kit).&lt;/p&gt;
&lt;p&gt;You can use the &lt;a href=&quot;https://material.angular.io/cdk/categories&quot;&gt;CDK&lt;/a&gt; to develop custom components. In this post, we will explore how to leverage this to create a toast service that can be used to show toast messages throughout your application.&lt;/p&gt;
&lt;h3 id=&quot;setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setup&quot; aria-label=&quot;setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#setup&quot; aria-label=&quot;setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup&lt;/h3&gt;
&lt;p&gt;First, we need to add CDK as a dependency to our project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; @angular/cdk&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or if you prefer npm:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; @angular/cdk&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can use what we need from the CDK. We’ll mainly use the &lt;a href=&quot;https://material.angular.io/cdk/overlay/overview&quot;&gt;Overlay package&lt;/a&gt; that will allow us to open floating panels around the screen which is exactly what we need to show toast messages. Internally this package is using the &lt;a href=&quot;https://material.angular.io/cdk/portal/overview&quot;&gt;Portal package&lt;/a&gt; that allows us to render dynamic content throughout the application.&lt;/p&gt;
&lt;h3 id=&quot;toast-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#toast-component&quot; aria-label=&quot;toast component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#toast-component&quot; aria-label=&quot;toast component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Toast component&lt;/h3&gt;
&lt;p&gt;We can start with the basic thing that we need, meaning a toast component:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91044251&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast_v1-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast_v1.ts content, created by adrianfaciu on 04:51PM on July 30, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast_v1.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Component } from &amp;#39;@angular/core&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@Component({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  selector: &amp;#39;app-toast&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  template: `&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;div&amp;gt;This is a toast message&amp;lt;/div&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  `&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_v1-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_v1-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastComponent { }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/583a50845a7b8889b217c4428e7daa19/raw/f1a2f517c0ea9db860a39a0f1664b9e97e04132b/toast_v1.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/583a50845a7b8889b217c4428e7daa19#file-toast_v1-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast_v1.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;This is the simplest component possible, a selector and a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;div&gt;&lt;/code&gt; with some text. Further down, we’ll extend it to suit our needs. But for now we’ll focus on displaying it on the screen.&lt;/p&gt;
&lt;p&gt;First thing after we have a component is to add it to an NgModule. In this case since we’ll not use the component directly in a template we’ll have to also add it to the entryComponents list, otherwise, the compiler will notice it’s not used and will remove it from the final bundle.&lt;/p&gt;
&lt;p&gt;Since we’re good citizens and we can think like we’re creating a library we can create a module file just for this toast component:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91044357&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-module_v1-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.module_v1.ts content, created by adrianfaciu on 04:57PM on July 30, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.module_v1.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { NgModule } from &amp;#39;@angular/core&amp;#39;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastComponent } from &amp;#39;./toast.component&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@NgModule({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  declarations: [ToastComponent],&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  entryComponents: [ToastComponent]&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v1-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastModule { }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/665a6ed4e111f5ef8669140aad4b242f/raw/358d71426cee69d9d891a359e3812eb6dc3f6d27/toast.module_v1.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/665a6ed4e111f5ef8669140aad4b242f#file-toast-module_v1-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.module_v1.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The only thing left to do with this module is add it in the imports array of our main application module.&lt;/p&gt;
&lt;h3 id=&quot;toast-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#toast-service&quot; aria-label=&quot;toast service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#toast-service&quot; aria-label=&quot;toast service permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Toast service&lt;/h3&gt;
&lt;p&gt;Now that we have a component and a module for our toast, we can start thinking about what we need next. From our application, we want to programmatically show toast messages whenever it’s needed. So the best option for this would be a toast service:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91044533&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-service_v1-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.service_v1.ts content, created by adrianfaciu on 05:05PM on July 30, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.service_v1.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Injectable } from &amp;#39;@angular/core&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@Injectable({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  providedIn: &amp;#39;root&amp;#39;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastService {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  show() { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v1-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/6105f06ac20ce6757c7d1c10506037ff/raw/c99c5b9065b5bbad92c4fc7a89149105ae32cec8/toast.service_v1.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/6105f06ac20ce6757c7d1c10506037ff#file-toast-service_v1-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.service_v1.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;We have a simple service with an empty (for now) method &lt;em&gt;show&lt;/em&gt;. The only notable thing is that we use the new &lt;em&gt;providedIn&lt;/em&gt; attribute of the Injectable decorator that’s available since Angular 6, specifying ‘root’ as a value. This means that this service will be registered as a singleton in our application, and that we don’t need to add it to the providers array anymore.&lt;/p&gt;
&lt;p&gt;This actually means that our services are now &lt;em&gt;tree-shakeable&lt;/em&gt;. If we have a service defined in our application, but it’s not referenced in any other place, it will be removed from the final bundle. This was not the case when we had to add them to the providers array of a module. Angular itself is starting to move its built-in services to this way of registering them and I suggest you start doing it as well.&lt;/p&gt;
&lt;p&gt;And now to our show toast method: we’ll need to get an instance of the Overlay service, create an instance of our toast component, and display it somewhere on the screen.&lt;/p&gt;
&lt;p&gt;We can achieve this with three lines of code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; overlayRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; toastPortal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentPortal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ToastComponent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
overlayRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toastPortal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First, we create an overlay using the &lt;a href=&quot;https://material.angular.io/cdk/overlay/api&quot;&gt;&lt;em&gt;create&lt;/em&gt; method&lt;/a&gt; on the overlay service. This will create a container in our application that will host our toast message. We get back &lt;em&gt;a reference&lt;/em&gt; to this container that we can use to control it.&lt;/p&gt;
&lt;p&gt;Secondly, we have to create an instance of our toast component. Since we’re trying to dynamically render a component, we can use the portal package to achieve this. We import the &lt;strong&gt;ComponentPortal&lt;/strong&gt; class from @angular/cdk/portal and we create a new instance passing our toast component class as an argument. This will create an instance of our component and give us back a wrapper that we can use to handle it.&lt;/p&gt;
&lt;p&gt;The last thing we need to do in order to show our toast is to get our toast portal and attach it to the overlay container that we previously created.&lt;/p&gt;
&lt;p&gt;Now, if we call the show method on our toast service in our app we’ll see a div with a text added to our application. But it does not look like a floating container or a toast. Let’s quickly fix this.&lt;/p&gt;
&lt;p&gt;The default positioning classes used by the overlay container are exported from CDK so that we can use them. Either we import them or create some custom ones. Since I’m always in favor of reusing functionality, we’ll import the existing ones.&lt;/p&gt;
&lt;p&gt;We can go to our main &lt;strong&gt;styles.css&lt;/strong&gt; file and import the prebuilt overlay css there:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;~@angular/cdk/overlay-prebuilt.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we use scss we can import it too, but we’ll also have to call the mixin. Otherwise, nothing will happen:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;~@angular/cdk/overlay&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@include&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cdk-overlay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we call our method, we’ll see that the message is floating in our top left corner. If we call the method multiple times, we’ll notice that we can see only one message, while previously they would stack one beneath the other. We can see only one because by default now they are placed on top of each other.&lt;/p&gt;
&lt;p&gt;In order to make it look more like a toast, we’ll add some basic styling (similar to what Bootstrap has) and use some of the icons that Angular Material provides.&lt;/p&gt;
&lt;p&gt;Our toast component will look a bit more complex now:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92578042&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-component_v2-html&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-html  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.component_v2.html content, created by adrianfaciu on 02:20PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.component_v2.html&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v2-html-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v2-html-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;div class=&amp;quot;toast&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v2-html-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v2-html-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;mat-icon&amp;gt;done&amp;lt;/mat-icon&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v2-html-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v2-html-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;div&amp;gt;This is a toast message&amp;lt;/div&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v2-html-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v2-html-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;mat-icon (click)=&amp;quot;close()&amp;quot;&amp;gt;close&amp;lt;/mat-icon&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v2-html-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v2-html-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;/div&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/45abbc822b333e8b226f31221c615a36/raw/219d1fab92af1678e9c223a588a154950de6bef3/toast.component_v2.html&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/45abbc822b333e8b226f31221c615a36#file-toast-component_v2-html&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.component_v2.html
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Now we have defined the toast CSS class to make it look a bit more like a toast message:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92578048&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-component_v1-css&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-css  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.component_v1.css content, created by adrianfaciu on 02:21PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.component_v1.css&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;.toast {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  position: relative;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  display: flex;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  justify-content: space-around;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  margin-bottom: 20px;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  padding: 10px 15px 10px 48px; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  width: 290px;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  background: #fff;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  border-width: 1px;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  border-style: solid;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  border-color: #dddddd #d6d6d6 #cfcfcf;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.11);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-css-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-css-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/2c9be4327ca9200d981c9c99c3f1516b/raw/3f456668282f9ccb1d2fa296807458a0163db18a/toast.component_v1.css&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/2c9be4327ca9200d981c9c99c3f1516b#file-toast-component_v1-css&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.component_v1.css
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;I assume we don’t always want to show the text “This is a toast” when displaying the message. We’ll make this configurable so that each time we call the show method we can pass in what text we want to show.&lt;/p&gt;
&lt;p&gt;Since we’ll extend this further on, let’s create an interface to represent the data we might send:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ToastData&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For now, it’s OK if we just have the text there. We also update the calls to our service with something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;toastService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Everything is ok!&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we have to pass this data to our component, somehow. We’re going to achieve this using Angular’s dependency injection system. In the toast component class we’ll add it to the constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ToastComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ToastData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we’ll use it in the component’s template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ data.text }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also have to make sure we add this data to the component injector so we have to update our toast service a bit. Thankfully, when we create the component portal (for the toast) we can pass in an injector that will be attached to it. Angular CDK provides a &lt;a href=&quot;https://github.com/angular/material2/blob/47de296116b4fdc9ee813a923a9e6a8534e18ee5/src/cdk/portal/portal-injector.ts#L16&quot;&gt;PortalInjector class&lt;/a&gt; which extends the basic Injector one from Angular so we’ll use it.&lt;/p&gt;
&lt;p&gt;First, we create a map with the custom tokens we want to add in the injector and then instantiate the PortalInjector:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tokens &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
tokens&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ToastData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; injector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PortalInjector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentInjector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tokens&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first parameter of the portal injector constructor is a *parent injector, *and we can get an instance of it using dependency injection. This is used to retrieve any dependencies that we don’t add to the custom tokens and we use in the toast component.&lt;/p&gt;
&lt;p&gt;Then we can create our component portal with our injector attached:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; toastPortal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ComponentPortal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ToastComponent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; injector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But if we try it, we’ll notice it won’t work yet. ToastData is an interface which is not a valid object for our map. There are two options here, one would be to make it a &lt;em&gt;class&lt;/em&gt;, and everything will work. Or, we can create a custom &lt;a href=&quot;https://angular.io/api/core/InjectionToken&quot;&gt;InjectionToken&lt;/a&gt; and use that one when we create the map and require the data.&lt;/p&gt;
&lt;p&gt;If we want to go for the injection token, we’ll have to create it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TOAST_DATA&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InjectionToken&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ToastData&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TOAST_DATA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Use it in our map:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;tokens&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TOAST_DATA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we also update the constructor for the Toast component to use the inject decorator:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Inject&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TOAST_DATA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ToastData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now our toast is configurable and we can pass in whatever text we want.&lt;/p&gt;
&lt;p&gt;As a bonus to this, it would be easy enough to configure the type of toast we’re showing and maybe display a different image based on that.&lt;/p&gt;
&lt;p&gt;We can define our toast type as one of success, info or warning. We left error out because it’s not a good UX practice to show errors in the form of a toast.&lt;/p&gt;
&lt;p&gt;We can create a TypeScript union type to represent this information:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ToastType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;warning&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;info&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And extend our ToastData to include it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ToastData&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ToastType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we want to show a toast message we also specify the type:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;toastService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Everything is ok!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;success&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can use any icons you want but, in our case, we’ll go with the ones provided by the Material library. If we don’t have it already we need to make sure we have the material module added as a dependency:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; @angular/material&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we have to add the icon font to our HTML file by including this line:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://fonts.googleapis.com/icon?family=Material+Icons&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add the Material icon module to our imports:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91160192&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-module_v2-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.module_v2.ts content, created by adrianfaciu on 05:25PM on August 05, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.module_v2.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { NgModule } from &amp;#39;@angular/core&amp;#39;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { OverlayModule } from &amp;#39;@angular/cdk/overlay&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { MatIconModule } from &amp;#39;@angular/material/icon&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastComponent } from &amp;#39;./toast.component&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@NgModule({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  imports: [OverlayModule, MatIconModule],&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  declarations: [ToastComponent],&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  entryComponents: [ToastComponent]&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-module_v2-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastModule { }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/a91c9a700afd697b5b5f067bf0898609/raw/90dbd173f5e1057ae065accc8c862c54c4f19ecf/toast.module_v2.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/a91c9a700afd697b5b5f067bf0898609#file-toast-module_v2-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.module_v2.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;And finally, we’re able to display an icon:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mat-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;info&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mat-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The names of the icons we want to show are identical for two of our toast types (warning and info), but when we have a success toast type we want to show a &lt;em&gt;done&lt;/em&gt; icon. We can easily fix this by creating a local property in the component and initializing it in the constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;iconType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;success&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;done&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Updated image usage:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mat-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; {{ iconType }} &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mat-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;OK, we have a toast message. Now how do we get rid of it? We have to implement some self-closing logic and allow it to be closed both from the UI and programmatically.&lt;/p&gt;
&lt;p&gt;In order to make sure we can close the toast from the UI we have to add a close icon/button. We can do that by adding it in the template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mat-icon&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;(click)&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;close()&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;close&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mat-icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now really, how do we close the toast? It looks like it’s not that complicated at all. We show the toast using an overlay, and when we create the overlay we get an instance of an overlay reference back. We can use this to do several things, including destroying it by calling the dispose method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlayRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dispose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Similar to how we got an overlay reference instance when creating one, we also want to create a toast reference that we can use and return using our service. The only thing we need in it now is the close method:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91202912&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-overlay-ref_v1-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;overlay-ref_v1.ts content, created by adrianfaciu on 05:24PM on August 07, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;overlay-ref_v1.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { OverlayRef } from &amp;#39;@angular/cdk/overlay&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastRef {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(readonly overlay: OverlayRef) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  close() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    this.overlay.dispose();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-overlay-ref_v1-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/e576832c66f8296ea2d4780015d50e28/raw/169f500494436080f990784693ca14f67f0e77e3/overlay-ref_v1.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/e576832c66f8296ea2d4780015d50e28#file-overlay-ref_v1-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          overlay-ref_v1.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;We pass in the overlay reference and only expose the close method that will call dispose. We’ll use it in two places from the start. We’ll return it to the user from the show method of the toast service. And, we’ll pass it to the toast component so it can close itself:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91202947&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-service_v2-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.service_v2.ts content, created by adrianfaciu on 05:26PM on August 07, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.service_v2.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Injectable, Injector } from &amp;#39;@angular/core&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Overlay } from &amp;#39;@angular/cdk/overlay&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ComponentPortal, PortalInjector } from &amp;#39;@angular/cdk/portal&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastComponent } from &amp;#39;./toast.component&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastData } from &amp;#39;./toast-config&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastRef } from &amp;#39;./toast-ref&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@Injectable({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  providedIn: &amp;#39;root&amp;#39;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastService {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(private overlay: Overlay, private parentInjector: Injector) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  showToast(data: ToastData) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    const overlayRef = this.overlay.create();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    const toastRef = new ToastRef(overlayRef);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    const injector = this.getInjector(data, toastRef, this.parentInjector);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    const toastPortal = new ComponentPortal(ToastComponent, null, injector);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L21&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L22&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    overlayRef.attach(toastPortal);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L23&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L24&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;24&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC24&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    return toastRef;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L25&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;25&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC25&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L26&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;26&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC26&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L27&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;27&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC27&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   getInjector(data: ToastData, toastRef: ToastRef, parentInjector: Injector) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L28&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;28&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC28&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    const tokens = new WeakMap();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L29&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;29&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC29&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L30&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;30&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC30&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    tokens.set(ToastData, data);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L31&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;31&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC31&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    tokens.set(ToastRef, toastRef);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L32&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;32&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC32&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L33&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;33&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC33&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    return new PortalInjector(parentInjector, tokens);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L34&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;34&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC34&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-L35&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;35&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-service_v2-ts-LC35&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/1d236460c858362d889b4fd5a3110d81/raw/394a667f61fdf507feb06ac7965a874fdc3bb722/toast.service_v2.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/1d236460c858362d889b4fd5a3110d81#file-toast-service_v2-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.service_v2.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Instantiate it by passing the overlay reference, return it from the method and add it to the tokens when we create the injector.&lt;/p&gt;
&lt;p&gt;In the toast component, we implement the close method. When the user clicks the close icon we actually do something and use a setTimeout to automatically hide the toast after an interval:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist91203022&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-component_v1-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.component_v1.ts content, created by adrianfaciu on 05:31PM on August 07, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.component_v1.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Component, OnInit, OnDestroy } from &amp;#39;@angular/core&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastData } from &amp;#39;./toast-config&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { ToastRef } from &amp;#39;./toast-ref&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@Component({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  selector: &amp;#39;app-toast&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  templateUrl: &amp;#39;./toast.component.html&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastComponent implements OnInit, OnDestroy {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  iconType: string;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  private intervalId: number;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(readonly data: ToastData, readonly ref: ToastRef) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    this.iconType = data.type === &amp;#39;success&amp;#39; ? &amp;#39;done&amp;#39; : data.type;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  ngOnInit() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    this.intervalId = setTimeout(() =&amp;gt; this.close(), 5000);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L21&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L22&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L23&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  ngOnDestroy() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L24&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;24&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC24&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    clearTimeout(this.intervalId);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L25&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;25&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC25&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L26&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;26&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC26&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L27&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;27&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC27&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  close() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L28&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;28&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC28&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    this.ref.close();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L29&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;29&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC29&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-L30&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;30&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v1-ts-LC30&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/c08dfb6daa20092b4f527cbcb3180b1e/raw/96db07b551b84f7bea3cc777321e985b00e63c51/toast.component_v1.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/c08dfb6daa20092b4f527cbcb3180b1e#file-toast-component_v1-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.component_v1.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Awesome! Let’s make some changes to correctly show toasts one beneath the other.&lt;/p&gt;
&lt;h3 id=&quot;multiple-toast-messages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#multiple-toast-messages&quot; aria-label=&quot;multiple toast messages permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#multiple-toast-messages&quot; aria-label=&quot;multiple toast messages permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Multiple toast messages&lt;/h3&gt;
&lt;p&gt;Since we want to show the next toast relative to the last one that was shown, it will be useful to remember the last one created. So let’s create a private variable *lastToast *and store the reference to the last toast created.&lt;/p&gt;
&lt;p&gt;And now that we have this reference we need to add another method on it that will allow us to get the position of the toast message on the screen:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPosition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlayElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have an instance of the overlay class and it has the overlayElement property that is the actual HTML element. From that, we can use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot;&gt;getBoundingClientRect method&lt;/a&gt; to get the actual size and position of the element. We will use this to know where the last element is displayed on the screen and show the next one in the correct position.&lt;/p&gt;
&lt;p&gt;Let’s configure the toast service to show toasts where we want. When calling the create method on the overlay service we can also pass in a &lt;a href=&quot;https://github.com/angular/material2/blob/master/src/cdk/overlay/overlay-config.ts&quot;&gt;config object&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Conveniently the overlay service has a position method for us to use that will expose in a fluent API style all the options that we can set. For example, if we want to show our toasts on the right side of the screen, relative to the global window we can do something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; positionStrategy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlay
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then pass this in when creating the overlay:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; overlayRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlay&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  positionStrategy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In order to stack the toast messages below each other, we have to add a top position and compute it. We’ll use the getPosition method we’ve added in the toast reference class for this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getPosition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastToast &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastToast&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPosition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; position &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;px&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If there is a last toast, we get the bottom position from that one. If not, we use 0 or a default value. Since the position API expects a CSS style value we have to add ‘px’ and convert the whole result to a string.&lt;/p&gt;
&lt;p&gt;Adding this to the initial position creation strategy:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overlay
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPosition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool! All the toast messages show up nicely and in order. 👍&lt;/p&gt;
&lt;h3 id=&quot;dynamic-content&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dynamic-content&quot; aria-label=&quot;dynamic content permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#dynamic-content&quot; aria-label=&quot;dynamic content permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dynamic content&lt;/h3&gt;
&lt;p&gt;For sure there will be some cases where a simple text message is not enough. Maybe we want to show an anchor tag or even a button, or something more complex in our toast. For this, we’ll add support for templates.&lt;/p&gt;
&lt;p&gt;First, we extend the ToastData object that we passed into our show method inside the toast service so that we can either pass in a text that we want to show or a template reference, optionally with a context object:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92581299&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast_data-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast_data.ts content, created by adrianfaciu on 07:16PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast_data.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ToastData {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  type: ToastType;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  text?: string;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  template?: TemplateRef&amp;lt;any&amp;gt;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  templateContext?: {};&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_data-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_data-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/6e1857694d0128f1881139338b9b5b0c/raw/d13ed82cce3e20d0d46ce47fdf6bb9d82ec3ff85/toast_data.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/6e1857694d0128f1881139338b9b5b0c#file-toast_data-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast_data.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;We marked all three of text, template, and templateContext as options so we can pass in either of them. One might want to treat the case when nothing is passed in though. 😄&lt;/p&gt;
&lt;p&gt;With this in place, we have to update the template of our toast message to account for this new template reference that might be used. In order to obtain this, we’ll use the &lt;a href=&quot;https://blog.angularindepth.com/use-ng-template-c72852c37fba&quot;&gt;ng-template component&lt;/a&gt; provided by Angular:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92581342&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-component_v3-html&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-html  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.component_v3.html content, created by adrianfaciu on 07:19PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.component_v3.html&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;ng-container *ngIf=&amp;quot;data.text; else templateRef&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  {{ data.message }}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;/ng-container&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;ng-template #templateRef&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;ng-container *ngTemplateOutlet=&amp;quot;data.template; context: data.templateContext&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;/ng-container&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;/ng-template&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/f25d269e2e3875204d6e1fb11fbe6852/raw/a1619f89dc5103050701a9c972fb2105d6becd6b/toast.component_v3.html&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/f25d269e2e3875204d6e1fb11fbe6852#file-toast-component_v3-html&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.component_v3.html
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;We have a container that we show only if we have a text property. If not, we just show the template also providing the context.&lt;/p&gt;
&lt;p&gt;And that’s it. Now we can also pass template references to our toast service.&lt;/p&gt;
&lt;h3 id=&quot;animations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#animations&quot; aria-label=&quot;animations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#animations&quot; aria-label=&quot;animations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Animations&lt;/h3&gt;
&lt;p&gt;That’s all good and nice, but we can make our toast message even more awesome. How? By adding animations! 😃&lt;/p&gt;
&lt;p&gt;The Angular animations API is easy to use and you can quickly create nice effects with it. For a detailed introduction check out &lt;a href=&quot;https://angular.io/guide/animations&quot;&gt;the official docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In our case, we’ll add two simple fade in and fade out animations for our toast messages.&lt;/p&gt;
&lt;p&gt;In order for this to work you need to import the &lt;a href=&quot;https://angular.io/api/platform-browser/animations/BrowserAnimationsModule&quot;&gt;BrowserAnimationsModule&lt;/a&gt; and use it in your application:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BrowserAnimationsModule &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/platform-browser/animations&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NgModule&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    imports&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; BrowserAnimationsModule &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CoreModule&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, we can go on and create some animations. I find it best to isolate different things in different files so we can create a file where we specify our animations:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92578401&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-animation-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast-animation.ts content, created by adrianfaciu on 02:56PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast-animation.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    AnimationTriggerMetadata,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    trigger,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    state,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    transition,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    style,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    animate,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;} from &amp;#39;@angular/animations&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const toastAnimations: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    readonly fadeToast: AnimationTriggerMetadata;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;} = {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    fadeToast: trigger(&amp;#39;fadeAnimation&amp;#39;, [&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        state(&amp;#39;in&amp;#39;, style({ opacity: 1 })),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        transition(&amp;#39;void =&amp;gt; *&amp;#39;, [style({ opacity: 0 }), animate(&amp;#39;{{ fadeIn }}ms&amp;#39;)]),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        transition(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            &amp;#39;default =&amp;gt; closing&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            animate(&amp;#39;{{ fadeOut }}ms&amp;#39;, style({ opacity: 0 })),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        ),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    ]),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L21&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;};&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L22&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-animation-ts-L23&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-animation-ts-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export type ToastAnimationState = &amp;#39;default&amp;#39; | &amp;#39;closing&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/0a39c14da637d6e5dd5c225f7ddee4c5/raw/433d3904f28a5817588c6634bb087fb5082bb3f7/toast-animation.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/0a39c14da637d6e5dd5c225f7ddee4c5#file-toast-animation-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast-animation.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;If we ignore the imports, which are almost half of the code, the rest is not that complicated.&lt;/p&gt;
&lt;p&gt;We have a toastAnimations object with a fadeToast property. We use the trigger method to specify the name of this animation and some metadata about it.&lt;/p&gt;
&lt;p&gt;Firstly, we specify the style that we want to have in the default state, mainly that we want opacity to be 1. Then we specify the two transitions that we care about. Basically, when the element will be shown which can be represented with the void =&gt; ** *expression. And, one when the state will change from &lt;em&gt;defaul&lt;/em&gt;t to *closing. _Now we could have tried to use the reverse and express the transition as _ =&gt; void* *which is also perfectly valid. Although, it would not have helped us much since the element would have already been removed, so there would not be anything to animate.&lt;/p&gt;
&lt;p&gt;Inside the animate methods we specify the duration of the animation, but since we want to make this configurable we use something similar to interpolation to specify a value:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;{{ fadeIn }}ms&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we have defined a union type to specify the state in which our animation can be: default or closing.&lt;/p&gt;
&lt;p&gt;Inside our toast component we have to add the animation to the animations array of the component decorator and declare an animationState property to hold the current value:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; toastAnimations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ToastAnimationState &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./toast-animation&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

animations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;toastAnimations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fadeToast&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

animationState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ToastAnimationState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;default&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this in place, we can update the template with the animation:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92578612&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast-component_v3-html&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-html  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast.component_v3.html content, created by adrianfaciu on 03:16PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast.component_v3.html&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;div class=&amp;quot;toast&amp;quot;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;     [@fadeAnimation]=&amp;quot;{value: animationState, params:&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        { fadeIn: 1000, fadeOut: 1000 }}&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;mat-icon&amp;gt;{{ iconType }}&amp;lt;/mat-icon&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;div&amp;gt;{{ data.text }}&amp;lt;/div&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &amp;lt;mat-icon (click)=&amp;quot;close()&amp;quot;&amp;gt;close&amp;lt;/mat-icon&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast-component_v3-html-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast-component_v3-html-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;/div&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/94944322a83427de4af69dd6882d1de7/raw/8b6be7604a1b0bef4781f18f00ea9db58d958a9d/toast.component_v3.html&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/94944322a83427de4af69dd6882d1de7#file-toast-component_v3-html&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast.component_v3.html
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;We have to use the trigger name that we defined for our animation, in our case *fadeAnimation *and bind an object to it, similar to property binding. Inside the object we specify two properties: the value that is bound to our component property that holds the animations state, and a params property where we specify configurable values that we use inside the animation.&lt;/p&gt;
&lt;p&gt;The only thing left to do is to update our code so that the fade out animation is also visible. Right now we just remove the element from the screen, we’ll have to manually update the state property for this.&lt;/p&gt;
&lt;p&gt;When our component was initialized we created a timer that will dispose the toast. What we want to do is start the animation instead, something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ngOnInit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;intervalId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;animationState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;closing&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we handle the animation done event to actually close the toast. Add the event handler inside the HTML template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;(@fadeAnimation.done)=&quot;onFadeFinished($event)&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Create the function that will take care of this:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92578795&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-fade_out_handler-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;fade_out_handler.ts content, created by adrianfaciu on 03:30PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;fade_out_handler.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    onFadeFinished(event: AnimationEvent) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const { toState } = event;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const isFadeOut = (toState as ToastAnimationState) === &amp;#39;closing&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const itFinished = this.animationState === &amp;#39;closing&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        if (isFadeOut &amp;amp;&amp;amp; itFinished) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            this.close();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fade_out_handler-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/c0bbe0ae1c1d68cb88eee3f52122bb41/raw/0b91c4043aaef7f6b9a0fab896fd6c399e7a88cd/fade_out_handler.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/c0bbe0ae1c1d68cb88eee3f52122bb41#file-fade_out_handler-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          fade_out_handler.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;As a bonus, you could reset the time whenever the user moves the mouse on a toast message. 😉&lt;/p&gt;
&lt;h3 id=&quot;global-configuration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#global-configuration&quot; aria-label=&quot;global configuration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#global-configuration&quot; aria-label=&quot;global configuration permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Global configuration&lt;/h3&gt;
&lt;p&gt;Maybe we want to configure the margin from the top/right where we show the toast message, or the fade in fade out animations time. We should do this in a simple and consistent way throughout our application.&lt;/p&gt;
&lt;p&gt;A perfect place to set a global config would be the NgModule we created for our toast. We create a &lt;em&gt;forRoot&lt;/em&gt; method and we allow the consumers to specify a config object.&lt;/p&gt;
&lt;p&gt;Firstly we should define an interface for this toast config object, something like:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92580898&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast_config-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast_config.ts content, created by adrianfaciu on 06:39PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast_config.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export interface ToastConfig {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    position?: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        top: number;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        right: number;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    };&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    animation?: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        fadeOut: number;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        fadeIn: number;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    };&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/cb3d3f9a59c45b06d662234edaf2bfc7/raw/86083133ecb3dccf6eec02aaeaa3db42376b54a8/toast_config.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/cb3d3f9a59c45b06d662234edaf2bfc7#file-toast_config-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast_config.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Also we should provide some default values that we can use when setting things up in case nothing is specified:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92580913&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast_config_default-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast_config_default.ts content, created by adrianfaciu on 06:41PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast_config_default.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const defaultToastConfig: ToastConfig = {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    position: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        top: 20,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        right: 20,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    animation: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        fadeOut: 2500,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        fadeIn: 300,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_config_default-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_config_default-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;};&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/a68033c9107d6ef57c3bff853bb69c45/raw/7f94464fd17a82696110108fb5a4dd3097bd8b4b/toast_config_default.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/a68033c9107d6ef57c3bff853bb69c45#file-toast_config_default-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast_config_default.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Now back to our module file, we can implement the forRoot method that will accept an argument of type ToastConfig and add it to the providers array so we can use it in our service:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist92580950&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-toast_for_root-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;toast_for_root.ts content, created by adrianfaciu on 06:43PM on October 21, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;toast_for_root.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  public static forRoot(config = defaultToastConfig): ModuleWithProviders {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      return {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;          ngModule: ToastModule,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;          providers: [&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;              {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                  provide: TOAST_CONFIG_TOKEN,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                  useValue: { ...defaultToastConfig, ...config },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;              },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;          ],&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      };&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-toast_for_root-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-toast_for_root-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/0311ab00e836066d6a02690873f43db0/raw/5a3452d99344092ffe706446bd933d52a288a698/toast_for_root.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/0311ab00e836066d6a02690873f43db0#file-toast_for_root-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          toast_for_root.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;If we don’t pass anything, we have the default value for the config. If we pass something, it might be just a part of the config that we want to overwrite, for example the positioning. So when we provide the value we destructure the default config and then overwrite any properties that were specified by the user.&lt;/p&gt;
&lt;p&gt;Once we have this in the providers, we can inject it in the toast service constructor and inside the toast component constructor so we can use the values:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Inject&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TOAST_CONFIG_TOKEN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;toastConfig&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ToastConfig&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can update the position methods to use the top and right properties from the config, and the animation inside the toast component template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fadeAnimation&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&quot;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; animationState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    params&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        fadeIn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toastConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fadeIn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        fadeOut&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toastConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fadeOut
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This way we have a nicely setup global configuration for our toast service. This can easily be extended to add any other properties we want and will allow this service to be used inside different projects that might have slightly different needs.&lt;/p&gt;
&lt;p&gt;As a different and probably cleaner alternative, one can created &lt;strong&gt;a single overlay&lt;/strong&gt; and a &lt;strong&gt;container component&lt;/strong&gt; that will be displayed in the overlay. All the toast messages can be added inside this container component and the template will be an &lt;strong&gt;ngIf&lt;/strong&gt; directive going over them. This can make working with positioning and animations easier. Thanks to &lt;a href=&quot;https://twitter.com/AlexOkrushko&quot;&gt;Alex Okrushko&lt;/a&gt; for the feedback and suggestion.&lt;/p&gt;
&lt;p&gt;Hope this helped and that you managed to read all the way to here 😉&lt;/p&gt;
&lt;p&gt;This is how our simple toast messages look and behave:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/toast-demo.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can see the &lt;strong&gt;code&lt;/strong&gt; &lt;a href=&quot;https://stackblitz.com/edit/angular-toast-service&quot;&gt;on StackBlitz&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[NgRx: tips & tricks]]></title><description><![CDATA[NgRx is one of the good options that developers choose to use in their Angular applications whenever the application grows a bit and something is needed to manage the state. While working with NgRx I’ve found out a series of tips that I would have loved to know beforehand.]]></description><link>https://adrianfaciu.dev/posts/ngrx-tips/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/ngrx-tips/</guid><pubDate>Wed, 09 May 2018 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/posts/ngrx-tips-cover.png&quot; alt=&quot;ngrx sample code&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2020&lt;/strong&gt;: NgRx has several new releases. Not everything written here is still up to date. I’ll try to update the article as I have time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ngrx/platform&quot;&gt;&lt;strong&gt;NgRx&lt;/strong&gt;&lt;/a&gt; is one of the good options that developers choose to use in their Angular applications whenever the application grows a bit and something is needed to manage the state.&lt;/p&gt;
&lt;p&gt;While working with &lt;a href=&quot;https://github.com/ngrx/platform&quot;&gt;NgRx&lt;/a&gt; I’ve found out a series of tips that I would have loved to know beforehand. Some of them I’ve discovered looking at different ways people were handling things and some I’ve found while constantly refactoring the code to make it cleaner and easier to understand.&lt;/p&gt;
&lt;p&gt;This series of tips is split into four categories, according to each part of NgRx that they apply to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;#actions&quot;&gt;Actions&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;#effects&quot;&gt;Effects&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;#reducers&quot;&gt;Reducers&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;#general&quot;&gt;General&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;actions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#actions&quot; aria-label=&quot;actions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#actions&quot; aria-label=&quot;actions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Actions&lt;/h2&gt;
&lt;h3 id=&quot;use-classes-for-all-actions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-classes-for-all-actions&quot; aria-label=&quot;use classes for all actions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#use-classes-for-all-actions&quot; aria-label=&quot;use classes for all actions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use classes for all actions&lt;/h3&gt;
&lt;p&gt;This will grant you awesome benefits like type safety in all the places where you use the action: components, reducers, effects, etc.&lt;/p&gt;
&lt;p&gt;This might feel a bit weird when you start using it, as one would prefer the less clutter way of factory methods, but using classes will pay off on the long run:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { Action } from &apos;[@ngrx/store](http://twitter.com/ngrx/store)&apos;;

export const LOG_ERROR = &apos;[Logger] Log Error&apos;;

export class LogError implements Action {
  readonly type = LOG_ERROR;
  constructor(readonly payload: { message: string }) { }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once we have this in place we can benefit in the reducer:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export function reducer(
    state = INITIAL_STATE,
    action: LogError | LogWarning,
){
    switch (action.type) {
        case LOG_ERROR:
            return {
                error: action.payload,
            };
        default:
            return state;
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case we are telling the reducer what kind of actions we expect and we use those in the switch statement below (read on to see how to group them together).&lt;/p&gt;
&lt;p&gt;One important thing there is that for TypeScript to be able to infer the type and allow us to benefit from this type of guards we must use &lt;strong&gt;readonly&lt;/strong&gt; on the &lt;strong&gt;type property&lt;/strong&gt; in the class. Normally it’s a property of type string, that can be changed as needed, but adding readonly will make it a &lt;a href=&quot;http://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types&quot;&gt;string literal&lt;/a&gt;, restricting the type to our specific string value and enabling the type guards.&lt;/p&gt;
&lt;p&gt;If you export the type declarations, beside readonly you also have to write the properties with an extra typeof:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;readonly type: typeof LOG_ERROR = LOG_ERROR;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Otherwise the type will be widen to string and that’s not what you want.&lt;/p&gt;
&lt;p&gt;We can also have the type guard in NgRx Effects, where it really helps:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@Effect()
logError$: Observable&amp;lt;Action&gt; = this.actions$.pipe(
    ofType&amp;lt;LogError&gt;(LOG_ERROR),
    tap(action =&gt; console.log(action.payload))
)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We used &lt;em&gt;ofType&lt;/em&gt; to specify the action that this effect will handle and from that point on we can be sure that the payload object is what we expect, meaning an object with the string property named message. This is really useful when you write or refactor the code because the compiler will show an error each time you make a mistake.&lt;/p&gt;
&lt;h3 id=&quot;always-name-the-property-of-the-action-payload&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#always-name-the-property-of-the-action-payload&quot; aria-label=&quot;always name the property of the action payload permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#always-name-the-property-of-the-action-payload&quot; aria-label=&quot;always name the property of the action payload permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Always name the property of the action payload&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;Action&lt;/em&gt; interface from NgRx states that our class needs to have only a property &lt;em&gt;type&lt;/em&gt; of type string. For consistency and some extra benefits, whenever a payload is needed in the action, we should name the property simply &lt;em&gt;payload.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Also, I always prefer to have the payload an object that has other properties even if just one. So for example, in the LogError case one can easily defined it like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;constructor(readonly payload:string ) { }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I find it more understandable to have an object and state what that value represents:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;constructor(readonly payload: { message: string }) { }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Inside a larger app one will have for sure actions that have objects as a payload. Using it like that all the time makes it consistent and easier to read and understand the intent.&lt;/p&gt;
&lt;h3 id=&quot;keep-all-related-actions-in-the-same-file&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#keep-all-related-actions-in-the-same-file&quot; aria-label=&quot;keep all related actions in the same file permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#keep-all-related-actions-in-the-same-file&quot; aria-label=&quot;keep all related actions in the same file permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Keep all related actions in the same file&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Given our logger actions example we can assume we have multiple actions. Even though generally it’s good to have &lt;strong&gt;a class per file&lt;/strong&gt;, in the case of NgRx Actions I find it better to have all the related actions in the same file.&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist88858184&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-logger-actions-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;logger.actions.ts content, created by adrianfaciu on 03:23PM on April 07, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;logger.actions.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Action } from &amp;#39;@ngrx/store&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const LOG_ERROR = &amp;#39;[Logger] Log Error&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const LOG_WARNING = &amp;#39;[Logger] Log Warning&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const LOG_INFO = &amp;#39;[Logger] Log Info&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class LogError implements Action {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  readonly type = LOG_ERROR;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(readonly payload: { message: string }) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class LogWarning implements Action {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  readonly type = LOG_WARNING;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(readonly payload: { message: string }) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class LogInfo implements Action {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  readonly type = LOG_INFO;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  constructor(readonly payload: { message: string }) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-logger-actions-ts-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-logger-actions-ts-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/eead8773ac3fa4bdb671cbae208e177b/raw/bff4599d8b440eb559469da2686584946eb6b536/logger.actions.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/eead8773ac3fa4bdb671cbae208e177b#file-logger-actions-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          logger.actions.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h3 id=&quot;group-actions-in-a-union-type&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#group-actions-in-a-union-type&quot; aria-label=&quot;group actions in a union type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#group-actions-in-a-union-type&quot; aria-label=&quot;group actions in a union type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Group actions in a union type&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Following the previous tip, we can group all the classes in a &lt;a href=&quot;http://www.typescriptlang.org/docs/handbook/advanced-types.html&quot;&gt;TypeScript union type&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export type LoggerActions = LogError | LogWarning | LogInfo;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will be helpful when we work with them and we want to state that some specific type can be any of the Logger actions without having to write all of them each time.&lt;/p&gt;
&lt;h3 id=&quot;use-short-names-for-constants-and-classes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-short-names-for-constants-and-classes&quot; aria-label=&quot;use short names for constants and classes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#use-short-names-for-constants-and-classes&quot; aria-label=&quot;use short names for constants and classes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Use short names for constants and classes&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In order to show better the intent we usually go for descriptive names. But in some cases this can get out of hand quickly and it could mess up the discoverability when we use code completion to find something.&lt;/p&gt;
&lt;p&gt;Suppose we have a Documents entity. We could create actions like DocumentsFetch, DocumentsFetchSuccess, DocumentsSortChanged with the corresponding constants named in the same way. However this will make most of our names quite long and when we want to use an action from here, everything will start with &lt;em&gt;Documents&lt;/em&gt; which is not that great.&lt;/p&gt;
&lt;p&gt;Since all of the actions are in separate files we can simply use shorter names for them. For constants:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export const FETCH = &apos;[Documents] Fetch&apos;;
export const FETCH_SUCCESS = &apos;[Documents] Fetch Success&apos;;
export const SORT_CHANGED = &apos;[Documents] Sort Changed&apos;;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have ‘[Documents]’ in front for all of the strings though. This string is actually the type of the action and we really want to have them different.&lt;/p&gt;
&lt;p&gt;Then we can name our actions in the same way: Fetch, FetchSuccess and SortChanged. Since they are all in the same file we can import everything at once:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import * as documentActions from &apos;./document.actions&apos;;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this way we sort of namespaced our actions and we always know which action from what type are we using.&lt;/p&gt;
&lt;h2 id=&quot;effects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#effects&quot; aria-label=&quot;effects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#effects&quot; aria-label=&quot;effects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Effects&lt;/h2&gt;
&lt;h3 id=&quot;implement-topayload-method&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#implement-topayload-method&quot; aria-label=&quot;implement topayload method permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#implement-topayload-method&quot; aria-label=&quot;implement topayload method permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Implement toPayload method&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This was actually a part of NgRx but was removed in newer versions. Since most of our actions have a payload property and usually in the transformations that are needed we care only about this, we can create a helper method that will map the action object to the payload:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const toPayload = &amp;lt;T&gt;(action: { payload: T }) =&gt; action.payload;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we can use it in our effects:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@Effect()
public errors$: Observable&amp;lt;Action&gt; = this.actions$
    .pipe(
        ofType(LOG_ERROR),
        map(toPayload),
        ...
     )&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After the map we can use the payload data without having to refer to it as action.payload.foo each time we want something from there.&lt;/p&gt;
&lt;p&gt;As a cleaner alternative we can use destructuring to fetch the payload property:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@Effect()
  public errors$: Observable&amp;lt;Action&gt; = this.actions$
    .pipe(
        ofType(LOG_ERROR),
        tap(({ payload }) =&gt; console.log(payload)),
        ...
     )&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;not-all-effects-have-to-emit-something&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#not-all-effects-have-to-emit-something&quot; aria-label=&quot;not all effects have to emit something permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#not-all-effects-have-to-emit-something&quot; aria-label=&quot;not all effects have to emit something permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Not all effects have to emit something&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Usually we create an effect to catch a specific action, do some processing and then emit one or more different actions. But we don’t have to do this all the time.&lt;/p&gt;
&lt;p&gt;We can specify that we don’t want to do this and just do some side effect whenever a certain action takes place:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@Effect({ dispatch: false })
userLogout$ = this.actions$.pipe(
   ofType&amp;lt;userActions.Logout&gt;(userActions.LOGOUT),
   tap(action =&gt; console.log(&apos;User is logging out&apos;, action))
)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see above this is handled by setting the dispatch property to false.&lt;/p&gt;
&lt;h3 id=&quot;load-data-with-effects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#load-data-with-effects&quot; aria-label=&quot;load data with effects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#load-data-with-effects&quot; aria-label=&quot;load data with effects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Load data with effects&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The purpose of an NgRx effect is to handle any side effects that we have in our application and one of this type of side effect is making AJAX calls to load data from an API. This is done by most developers using this library but I’m adding it here for completion.&lt;/p&gt;
&lt;p&gt;So instead of loading data directly we do this with an effect. Assuming the user has a button that can be pressed to load some documents, when this happens we simply trigger an action to notify that we want to do this: &lt;em&gt;documentActions.Fetch.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Inside an effect we catch this action, make the request and map the outcome to a success action:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;loadDocuments$ = this.actions$.pipe(
   ofType&amp;lt;documentActions.Fetch&gt;(documentActions.FETCH)
   switchMap(() =&gt;
       this.documentsService
           .getDocuments().pipe(
              map(docs =&gt; new documentActions.FetchSuccess(docs))
            )
    )
)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then we have a reducer that listens for this FetchSuccess action and puts the new documents in the state.&lt;/p&gt;
&lt;p&gt;In this way all the requests are isolated from our application and we have a central place to do each of them. We might have multiple places from which we can trigger a documents fetch and all we have to do is send the fetch action.&lt;/p&gt;
&lt;h3 id=&quot;always-handle-errors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#always-handle-errors&quot; aria-label=&quot;always handle errors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#always-handle-errors&quot; aria-label=&quot;always handle errors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Always handle errors&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The actions stream is an Observable, this means that once an error occurs it’s done, that’s it, no more events will occur and we really don’t want this since it will block our application.&lt;/p&gt;
&lt;p&gt;So we always need to make sure we handle things. This means making requests on a different stream that we then merge with operators like &lt;em&gt;switchMap&lt;/em&gt; and always handle errors there.&lt;/p&gt;
&lt;p&gt;So a more complete example of fetching the documents would be:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;loadDocuments$ = this.actions$.pipe(
   ofType&amp;lt;documentActions.Fetch&gt;(documentActions.FETCH)
   switchMap(() =&gt;
       this.documentsService
         .getDocuments().pipe(
            map(docs =&gt; new documentActions.FetchSuccess(docs)),
            catchError(err =&gt; of(new documentActions.FetchFailed()))
          )
    )
)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The actions stream is the main one that all our actions are emitted onto, so when we want to make a request to load the document, that might fail, we do it inside a &lt;em&gt;switchMap&lt;/em&gt; operator where we catch the error and return a different action.&lt;/p&gt;
&lt;h3 id=&quot;effects-are-services&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#effects-are-services&quot; aria-label=&quot;effects are services permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#effects-are-services&quot; aria-label=&quot;effects are services permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Effects are services&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is an easy thing to forget, but Effect are services in Angular world and we might use Dependency Injection to get instances of other services in them.&lt;/p&gt;
&lt;p&gt;For this to work we need to add the &lt;strong&gt;Injectable&lt;/strong&gt; decorator to the class.&lt;/p&gt;
&lt;h2 id=&quot;reducers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#reducers&quot; aria-label=&quot;reducers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#reducers&quot; aria-label=&quot;reducers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Reducers&lt;/h2&gt;
&lt;h3 id=&quot;keep-them-simple&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#keep-them-simple&quot; aria-label=&quot;keep them simple permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#keep-them-simple&quot; aria-label=&quot;keep them simple permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Keep them simple&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Here I have only one tip, keep reducers as simple as possible. They should be clean and don’t have any logic inside. A reducer should only take the data from the action and update the corresponding part in the state with it, it should not make any decisions or any kind of logic that will be &lt;em&gt;hidden&lt;/em&gt; there.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ngrx/platform/tree/master/example-app&quot;&gt;The official sample app&lt;/a&gt; exemplifies this in a good way, this is how a reducer should look:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist89437734&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-reducer-example-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;reducer-example.ts content, created by adrianfaciu on 10:51AM on May 08, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;reducer-example.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export function reducer(state = initialState, action: AuthActionsUnion): State {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  switch (action.type) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    case AuthActionTypes.LoginSuccess: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      return {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        ...state,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loggedIn: true,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        user: action.payload.user,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      };&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    case AuthActionTypes.Logout: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      return initialState;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    default: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      return state;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-reducer-example-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-reducer-example-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/7ea702e71e64114d574665672799fdab/raw/21f6a89642817e755a61da7361781515263d8839/reducer-example.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/7ea702e71e64114d574665672799fdab#file-reducer-example-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          reducer-example.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;If you have something that looks more complicated than this there is place to refactor and make it slightly better.&lt;/p&gt;
&lt;h2 id=&quot;general&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#general&quot; aria-label=&quot;general permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#general&quot; aria-label=&quot;general permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;General&lt;/h2&gt;
&lt;h3 id=&quot;use-selectors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-selectors&quot; aria-label=&quot;use selectors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#use-selectors&quot; aria-label=&quot;use selectors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Use selectors&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;On the store class we have the &lt;em&gt;select&lt;/em&gt; method, and there also is a pipeable select function. We can use both of them to fetch a part from the state in places where it’s needed.&lt;/p&gt;
&lt;p&gt;While you can pass the keys/path to what you want to fetch as a string argument to these functions I recommend using the &lt;em&gt;createSelector&lt;/em&gt; function provided by NgRx which, as the name suggests, allows us to create a callback function that knows how to fetch a part of the state.&lt;/p&gt;
&lt;p&gt;For example something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export const getLoggerErrors =
  createSelector(getLoggerState, (state) =&gt; state.errors);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where getLoggerState is a generic way to get the part of the state responsible for the router:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export const getLoggerState = (state: AppState) =&gt; state.logger;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then whenever we want to select something we use these kind of functions as an argument to select.&lt;/p&gt;
&lt;p&gt;This has several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;we can change the way our state looks behind the scenes without actually changing the app code, since the selector will be the same one&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we can group together different parts of the state and get what we need&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the selectors use a technique called &lt;a href=&quot;https://en.wikipedia.org/wiki/Memoization&quot;&gt;memoization&lt;/a&gt; which basically means that once we call one with some arguments it will store that result and whenever we call it again it will return the cached result without executing the function&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a lot of good info about selectors in &lt;a href=&quot;https://github.com/ngrx/platform/blob/master/docs/store/selectors.md&quot;&gt;the official docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;normalize-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#normalize-data&quot; aria-label=&quot;normalize data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#normalize-data&quot; aria-label=&quot;normalize data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Normalize data&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;We should think of the state like a local, in memory database. One important thing we should not do is duplicate the same information all over the place.&lt;/p&gt;
&lt;p&gt;So for example if we have a list of items we can keep it in one place and if we need a list of selected items we just hold a list of ids, those that are selected. Whenever we need them we create a selector that gets the list of items and the selected ids and map them together to get the result.&lt;/p&gt;
&lt;p&gt;This is important because we don’t want to update multiple parts in the state when one single action occurs.&lt;/p&gt;
&lt;p&gt;Also there should not be that many nested levels of data, as this will get tricky to manage and select when needed. A common approach here is that instead of keeping items in arrays, we keep them in objects and use the id as an identifier. This needs a bit of time to get used to but it pays of in the long run.&lt;/p&gt;
&lt;p&gt;If normalizing the state in this way gets too complicated to do by hand there is an awesome library called &lt;a href=&quot;https://www.npmjs.com/package/normalizr&quot;&gt;normalizr&lt;/a&gt; that can help a lot with this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
  result: &quot;123&quot;,
  entities: {
    &quot;articles&quot;: {
      &quot;123&quot;: {
        id: &quot;123&quot;,
        author: &quot;1&quot;,
        title: &quot;My awesome blog post&quot;,
        comments: [ &quot;324&quot; ]
      }
    },
    &quot;users&quot;: {
      &quot;1&quot;: { &quot;id&quot;: &quot;1&quot;, &quot;name&quot;: &quot;Paul&quot; },
      &quot;2&quot;: { &quot;id&quot;: &quot;2&quot;, &quot;name&quot;: &quot;Nicole&quot; }
    },
    &quot;comments&quot;: {
      &quot;324&quot;: { id: &quot;324&quot;, &quot;commenter&quot;: &quot;2&quot; }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is how a normalized state would look if we have a blog post containing articles, users and comments. Have a look at the &lt;a href=&quot;https://github.com/paularmstrong/normalizr&quot;&gt;normalizr documentation&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;Another benefit of keeping the state like this is that it will allow us, more easily, to add a caching layer to our application. Only loading data when we don’t have it, or what we have is outdated.&lt;/p&gt;
&lt;h3 id=&quot;dont-use-the-store-all-over-the-place&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dont-use-the-store-all-over-the-place&quot; aria-label=&quot;dont use the store all over the place permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#dont-use-the-store-all-over-the-place&quot; aria-label=&quot;dont use the store all over the place permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Don’t use the store all over the place&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is more about ‘dumb components’ than anything else. Most of our UI components should be small and dumb, meaning they should not know that there is a state, how we fetch data and so on.&lt;/p&gt;
&lt;p&gt;Generally we have &lt;em&gt;containers&lt;/em&gt;, meaning a parent component that fetches from the state all the required data and triggers all the required actions and all the small components inside only have a few Inputs and Outputs to handle what they need to display.&lt;/p&gt;
&lt;h3 id=&quot;generic-error-action&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#generic-error-action&quot; aria-label=&quot;generic error action permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#generic-error-action&quot; aria-label=&quot;generic error action permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Generic error action&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;When we load data using NgRx Effects we’ll end up having lots of actions that trigger the load, those that mark the load success and those that show when an error occured.&lt;/p&gt;
&lt;p&gt;We can make some of them generic, for example the error ones. In my experience we tend to use the other ones in more places and need them explicitly, but if this is not the case you can make those generic as well.&lt;/p&gt;
&lt;p&gt;For example this is how a generic error action would look:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist89426705&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-generic-error-action-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;generic-error-action.ts content, created by adrianfaciu on 07:54PM on May 07, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;generic-error-action.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class ErrorOccurred implements Action {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    readonly type = ERROR_OCCURRED;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    constructor(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        readonly payload: {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            action?: Action;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            error?: ErrorData;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    ) {}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-generic-error-action-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-generic-error-action-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/4c933da6e9d3439e1021b37d593bf123/raw/b51a5fc1fa173c6e59e2dbc63b0fd325712281de/generic-error-action.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/4c933da6e9d3439e1021b37d593bf123#file-generic-error-action-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          generic-error-action.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;It has a payload with an action property, this will specify which action triggered the error. For example if an error occurs while we were doing a FETCH_USERS action, this will be used here. We have it as an action with the type property inside for consistency and ease of usage, we could have just as easily have this as string and store the action type only.&lt;/p&gt;
&lt;p&gt;The error property is of type ErrorData and will hold more information about what went wrong. You can model this as need, for example I generally use something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;interface ErrorData {
  type?: string;
  error?: any;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then when we can use this in Effects where we handle the error case:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist89437768&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-load-doc-err-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;load-doc-err.ts content, created by adrianfaciu on 10:54AM on May 08, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;load-doc-err.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;loadDocuments$ = this.actions$.pipe(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   ofType&amp;lt;documentActions.Fetch&amp;gt;(documentActions.FETCH)&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   switchMap((action) =&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;       this.documentsService&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;         .getDocuments().pipe(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            map(docs =&amp;gt; new documentActions.FetchSuccess(docs)),&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            catchError(error =&amp;gt; of(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                  new ErrorOccurred({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                      action,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                      error,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                  })&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;              ))&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;          )&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    )&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-load-doc-err-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-load-doc-err-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;)&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/828b3ab47ba2a03a5032e639444fb1d7/raw/65d6a77977d4df7855a6f448f81087f922be6a50/load-doc-err.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/828b3ab47ba2a03a5032e639444fb1d7#file-load-doc-err-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          load-doc-err.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h3 id=&quot;property-initialization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#property-initialization&quot; aria-label=&quot;property initialization permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#property-initialization&quot; aria-label=&quot;property initialization permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;strong&gt;Property initialization&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Initialize directly all &lt;em&gt;selector&lt;/em&gt; properties when defining them instead of constructor or other places. One can have code like:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist89408361&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-prop-initialization-long-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;prop-initialization-long.ts content, created by adrianfaciu on 06:58PM on May 06, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;prop-initialization-long.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class DocumentContainer {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    companyName$: Observable&amp;lt;string&amp;gt;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    documentStatus$: Observable&amp;lt;number&amp;gt;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    constructor(&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        private store: Store&amp;lt;AppStore.AppState&amp;gt;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    ) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.companyName$ = this.store.select(detailsSelector.getDocumentCompanyName);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.documentStatus$ = this.store.select(detailsSelector.getDocumentStatus);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-long-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/db069c355e79e93f25ec27a369782e9f/raw/eaacde6971eb6b16cc1af77336e86fc2a524c82a/prop-initialization-long.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/db069c355e79e93f25ec27a369782e9f#file-prop-initialization-long-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          prop-initialization-long.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Where we first define the properties and then we initialize them in the constructor. Ideally we can do it in one place while having less code that is also easier to read. This would have the same effect:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist89408393&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-prop-initialization-short-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;prop-initialization-short.ts content, created by adrianfaciu on 07:02PM on May 06, 2018.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;prop-initialization-short.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class DocumentContainer {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    companyName$ = this.store.select(detailsSelector.getDocumentCompanyName);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    documentStatus$ = this.store.select(detailsSelector.getDocumentStatus);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    constructor(private store: Store&amp;lt;AppStore.AppState&amp;gt;) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-prop-initialization-short-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/5c4d8f58d162b847a009da08f0ccb074/raw/b7b7131f98e7fd2661394694b40a62e52e1aaf73/prop-initialization-short.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/5c4d8f58d162b847a009da08f0ccb074#file-prop-initialization-short-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          prop-initialization-short.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Hopefully you’ve found some good tips about using NgRx above 😃.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Barrel files: to use or not to use?]]></title><description><![CDATA[How to use barrel files in our projects. Should you use them? If yes, how to organize code around them and where to place these files. Read on to find out more.]]></description><link>https://adrianfaciu.dev/posts/barrel-files/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/barrel-files/</guid><pubDate>Sun, 04 Mar 2018 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/posts/barrel-files-cover.png&quot; alt=&quot;barrel files example code&quot;&gt;&lt;/p&gt;
&lt;p&gt;First of all, what are these &lt;strong&gt;barrel files&lt;/strong&gt;? Using ES2015 modules, we have files from which we export one or more things. Barrel files are a way to &lt;strong&gt;re-export&lt;/strong&gt; all or some of these from one, single, convenient place.&lt;/p&gt;
&lt;p&gt;You can understand better what they are and how they are used by looking at &lt;a href=&quot;https://basarat.gitbook.io/typescript/main-1/barrel&quot;&gt;this short example&lt;/a&gt; from the aswesome &lt;em&gt;TypeScript deep dive&lt;/em&gt; book.&lt;/p&gt;
&lt;p&gt;Barrel files are named &lt;em&gt;index,&lt;/em&gt; as convention, because most module loaders will look for this by default when &lt;a href=&quot;https://webpack.github.io/docs/resolving.html&quot;&gt;resolving absolute paths&lt;/a&gt; and this will allow us to omit the filename from the path and just point to a folder. Assuming we have a barrel file in a services folder we’ll import things like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { LoggerService, UserService } from &apos;app/core/services&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can use this anywhere in our app if we’re using an absolute path when importing, if you want to know more about this you can check my &lt;a href=&quot;https://adrianfaciu.dev/posts/module-imports/&quot;&gt;short post&lt;/a&gt; 😉&lt;/p&gt;
&lt;p&gt;There are people arguing that one does not need to use barrel files, at least inside Angular applications since we have &lt;a href=&quot;https://angular.io/api/core/NgModule&quot;&gt;NgModule&lt;/a&gt;. Even the &lt;a href=&quot;https://angular.io/guide/glossary#barrel&quot;&gt;official documentation&lt;/a&gt; hints towards this.&lt;/p&gt;
&lt;p&gt;While we can organize a lot of things with the help of Angular modules, I still prefer to also &lt;strong&gt;use a few barrel files&lt;/strong&gt; throughout the application. They greatly simplify the imports and make them look clearer. We just don’t want to have too many barrel files since that is counter productive and usually leads to &lt;em&gt;circular dependency&lt;/em&gt; issues which sometimes can be quite tricky to resolve.&lt;/p&gt;
&lt;p&gt;So a bad practice would be to create a barrel file inside each folder we have, this is something I would really &lt;strong&gt;not&lt;/strong&gt; &lt;strong&gt;recommend&lt;/strong&gt;. Tried it once to see how it goes, and let’s just say it did not end well 😃&lt;/p&gt;
&lt;p&gt;What I found to work is to have &lt;strong&gt;one level of barrel files&lt;/strong&gt; throughout the application structure. In some rare cases maybe a few more in some subfolders but that is a matter of preference.&lt;/p&gt;
&lt;p&gt;A good way to structure the application is to place files into folders based on features, and inside these folders create subfolders based on the type.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/barrel-1.png&quot; alt=&quot;project folders structure example&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the example above we have a core module, usually found inside &lt;a href=&quot;https://angular.io/guide/ngmodule#the-core-module&quot;&gt;Angular applications&lt;/a&gt;. Inside we have folders for each Angular specific types along with an Angular module.&lt;/p&gt;
&lt;p&gt;Similar structure for a feature module:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/barrel-2.png&quot; alt=&quot;project folders structure example&quot;&gt;&lt;/p&gt;
&lt;p&gt;Pretty much the same, with some more folders based on types.&lt;/p&gt;
&lt;p&gt;If we have this kind of structure we would want our barrel files inside these type folders. So each of them will have an index file where we re-export what is inside those folders. Then when we import we’ll have:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { DocumentModel, CommentModel } from &apos;app/+documents/models&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is short, we can import all the similar things from one place and we see pretty clear what they are. So if we need models from a specific feature we go feature folder name and models folder. If we need services to the same feature folder name and services and so on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everything should be clear and easy to find. If it’s &lt;strong&gt;not&lt;/strong&gt;, the structure and/or barrel files are wrong and should be changed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you look at an import and you don’t immediately understand what you are importing and from where it’s usually a smell that the structure is not that ok. Similar, if you want to import something and don’t know where to get it from.&lt;/p&gt;
&lt;p&gt;You should experiment with the structure and using barrel files until you find something that works, usually this is constantly needed as the application grows and evolves. &lt;strong&gt;Never be afraid to change things&lt;/strong&gt; in order to make them better 😃.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using the Angular Router to navigate to external links]]></title><description><![CDATA[How to use the Angular router to navigate to external pages. This is helpful to trigger guards and warn the user or save data.]]></description><link>https://adrianfaciu.dev/posts/angular-router-external-links/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/angular-router-external-links/</guid><pubDate>Wed, 14 Feb 2018 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Navigating to an external url from an Angular application is something quite easy. Using window.location or an anchor tag is straight forward, but it has a big disadvantage, it bypasses the Angular Router.&lt;/p&gt;
&lt;p&gt;This means that if we have something like &lt;strong&gt;route guards&lt;/strong&gt;, they will not be called. For example we might have a guard that notifies the user of any unsaved changes and can stop the navigation if the user wishes. If you want to know more about route guards, Thoughtram blog has a &lt;a href=&quot;https://blog.thoughtram.io/angular/2016/07/18/guards-in-angular-2.html&quot;&gt;nice article about this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So we need a nice and generic way of navigating to an external url but using the Router so that our guards will get called.&lt;/p&gt;
&lt;p&gt;We’re going to do this using a route resolver and a custom route. Resolve is used to fetch any required data before activating the route but we’ll hijack it a bit to navigate where we want.&lt;/p&gt;
&lt;p&gt;First, we need to define a new custom route in our routes config:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
    path: &apos;externalRedirect&apos;,
    resolve: {
        url: externalUrlProvider,
    },
    // We need a component here because we cannot define the route otherwise
    component: NotFoundComponent,
},&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have a new route with the &lt;em&gt;externalRedirect&lt;/em&gt; path, you can use here whatever string you want, as long as it’s not used by another route within the application.&lt;/p&gt;
&lt;p&gt;As an alternative to resolve we can also use the route guards for the same purpose. For example we hookup to the can activate route guard:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;canActivate: [externalUrlProvider]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have a fictional &lt;em&gt;url&lt;/em&gt; property that we’re supposed to provide before activating this route with a value set to *externalUrlProvider, *we’ll have a look at this in a second. And last a component, in this case one for a not found page, but it can really be anything, it’s there only because we cannot declare a route without it.&lt;/p&gt;
&lt;p&gt;The value of url, external url provider, is an injection token, we’ll use it in the Providers array to define our functionality:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const externalUrlProvider = new InjectionToken(&apos;externalUrlRedirectResolver&apos;);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And this is how our routing module might look:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@NgModule({
    providers: [
        {
            provide: externalUrlProvider,
            useValue: (route: ActivatedRouteSnapshot) =&gt; {
                const externalUrl = route.paramMap.get(&apos;externalUrl&apos;);
                window.open(externalUrl, &apos;_self&apos;);
            },
        },
    ],
    imports: [
        RouterModule.forRoot(routes),
    ],
    exports: [RouterModule],
})
export class AppRoutingModule {}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We create a function that gets as parameter the activated route, read a route parameter called externalUrl and then use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/open&quot;&gt;window.open&lt;/a&gt; to navigate to the provided link.&lt;/p&gt;
&lt;p&gt;Now we also have to use our new route when we want to navigate to an external url. While we can do this using directly the router:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;this.router.navigate([&apos;/externalRedirect&apos;, { externalUrl: url }]);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We might also want a more generic way. Maybe attach to all the anchor elements that have a href pointing to an external resource.&lt;/p&gt;
&lt;p&gt;We can create a directive with a selector ‘&lt;em&gt;a[appExternalUrl]’&lt;/em&gt; which means that it will work on all the anchor elements where we add the directive name as attribute.&lt;/p&gt;
&lt;p&gt;Then we’ll read the value of href and use the router to navigate to it. The complete version looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { Directive, HostListener, ElementRef } from &apos;@angular/core&apos;;
import { Router } from &apos;@angular/router&apos;;
import { isNil } from &apos;ramda&apos;;

@Directive({
    selector: &apos;a[appExternalUrl]&apos;,
})
export class ExternalUrlDirective {
    constructor(private el: ElementRef, private router: Router) {}

    @HostListener(&apos;click&apos;, [&apos;$event&apos;])
    clicked(event: Event) {
        const url = this.el.nativeElement.href;
        if (isNil(url)) {
            return;
        }

        this.router.navigate([&apos;/externalRedirect&apos;, { externalUrl: url }], {
            skipLocationChange: true,
        });

        event.preventDefault();
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have a constructor where we get an instance of the element and one for the router.&lt;/p&gt;
&lt;p&gt;Then we listen for the click event and read the href property of the element passing it along to the navigate method of the router to actually perform the navigation. We also specify ‘&lt;em&gt;&lt;strong&gt;skipLocationChange&lt;/strong&gt;&lt;/em&gt;’ as *true *when navigating since we don’t want the user to actually see our intermediary route, we use it just to trigger any router specific logic we might have in our app like the deactivation guards.&lt;/p&gt;
&lt;p&gt;Lastly, since we handled the click ourselves we call the &lt;em&gt;preventDefault&lt;/em&gt; method on the event.&lt;/p&gt;
&lt;p&gt;We can use our new directive wherever it’s needed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;a [href]=&quot;[https://www.google.com/](https://www.google.com/)&quot;
    appExternalUrl
&gt;Click Me&amp;lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While this might feel a bit like a hack, it does provide a good and generic way of navigating to external resources while also involving the Angular Router.&lt;/p&gt;
&lt;p&gt;You can find a sample implementation &lt;a href=&quot;https://stackblitz.com/edit/angular-external-links&quot;&gt;on StackBlitz&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Update on testing NgRx Effects]]></title><description><![CDATA[A while ago I’ve written a post on how to test NgRx effects. If you did not read that one I encourage you to go and have a look. Since then, both NgRx and RxJs have released some new versions and there are some things we need to update in our tests.]]></description><link>https://adrianfaciu.dev/posts/update-testing-ngrx/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/update-testing-ngrx/</guid><pubDate>Mon, 04 Dec 2017 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;A while ago I’ve written a post on how to test NgRx effects. If you did not read that one I encourage you to go and have a look.&lt;/p&gt;
&lt;p&gt;Since then, both &lt;a href=&quot;https://github.com/ngrx/platform&quot;&gt;NgRx&lt;/a&gt; and &lt;a href=&quot;https://github.com/reactivex/rxjs&quot;&gt;RxJs&lt;/a&gt; have released some new versions and there are some things we need to update in our tests.&lt;/p&gt;
&lt;h2 id=&quot;store-mock&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#store-mock&quot; aria-label=&quot;store mock permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#store-mock&quot; aria-label=&quot;store mock permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Store mock&lt;/h2&gt;
&lt;p&gt;Up to now we were creating the data for the store mock with one simple line of code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const initialAppState = reducer(undefined, { type: &apos;INIT_ACTION&apos; });&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We were fetching the root reducer, the result of calling combineReducers on all our reducers, and calling it with an unknown action so we would get the initial state in all the cases.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;4.x&lt;/strong&gt; release of &lt;strong&gt;NgRx&lt;/strong&gt; added, among others, the awesome option of placing reducers, effects and actions inside the modules where they were used and lazy load them when needed. So, as with other libraries, we use &lt;em&gt;forRoot&lt;/em&gt; method in the app module and &lt;em&gt;forFeature&lt;/em&gt; in all the rest.&lt;/p&gt;
&lt;p&gt;You can have a look at the &lt;a href=&quot;https://github.com/ngrx/platform/blob/master/MIGRATION.md&quot;&gt;migration guide here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This means that now we have to compose the reducers object from all our feature modules. We have to create a reducers map that looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const reducersMap = {

    ...coreReducers,

    items: fromItems.Reducer,

    itemDetails: fromItemDetails.Reducer,

};&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another change is that the forRoot method now takes this map of reducers as an argument, it will call internally combineReducers method. So we need to create the root reducer by calling this ourselves:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const rootReducer = combineReducers(reducersMap, initialState);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second argument, *initialState, *is an object that we can create in our tests, when a state different than the default is needed.&lt;/p&gt;
&lt;p&gt;After we have all this, we can create the state as we did before:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const appState = rootReducer(undefined, { type: &apos;INIT_ACTION&apos; });&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;rxjs-and-lettable-operators&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rxjs-and-lettable-operators&quot; aria-label=&quot;rxjs and lettable operators permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#rxjs-and-lettable-operators&quot; aria-label=&quot;rxjs and lettable operators permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RxJs and lettable operators&lt;/h2&gt;
&lt;p&gt;From RxJs 5.5 we have lettable operators, which means we import them as standalone functions and need the pipe method in order to use. You can read more about this in the &lt;a href=&quot;https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since they are functions, and no longer patch the Observable prototype when imported, it means we also cannot do this anymore in order to specify a scheduler, so we need to find an alternative.&lt;/p&gt;
&lt;p&gt;And this alternative it’s not that easy to find at the moment, there is no easy and clean way to do this without changing the code of the effect class.&lt;/p&gt;
&lt;h3 id=&quot;rebinding-schedule&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rebinding-schedule&quot; aria-label=&quot;rebinding schedule permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#rebinding-schedule&quot; aria-label=&quot;rebinding schedule permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Rebinding schedule&lt;/h3&gt;
&lt;p&gt;By default, RxJs operators use the async scheduler internally, if no other is specified. So a workaround to the problem is to change the behaviour of this scheduler. We can import it in our tests and overwrite the schedule method to that of our test scheduler:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { async } from &apos;rxjs/scheduler/async&apos;;
import { getTestScheduler } from &apos;jasmine-marbles&apos;;

const testScheduler = getTestScheduler();

async.schedule = (*work*, *delay*, *state*) =&gt;
          testScheduler.schedule(work, delay, state);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By running this in a &lt;em&gt;before&lt;/em&gt; block, we’ll make sure that our tests will still pass, and we can get rid of the code where we were patching individual operators.&lt;/p&gt;
&lt;h3 id=&quot;passing-scheduler-in-constructor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#passing-scheduler-in-constructor&quot; aria-label=&quot;passing scheduler in constructor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#passing-scheduler-in-constructor&quot; aria-label=&quot;passing scheduler in constructor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Passing scheduler in constructor&lt;/h3&gt;
&lt;p&gt;A similar approach to how the tests are done inside the &lt;a href=&quot;https://github.com/ngrx/platform/tree/master/example-app&quot;&gt;sample app&lt;/a&gt; from NgRx repository is to add a scheduler to the effect constructor. Either mark it with the &lt;a href=&quot;https://angular.io/api/core/Optional&quot;&gt;optional&lt;/a&gt; decorator and if we don’t get anything we initialize it to the async scheduler or we can use a default value for it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export class AppTimeEffect {
     constructor(private *actions$*: Actions,
                 private *scheduler* = async,
      ) { }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After we have it here we also need to pass it as argument to all the operators where it’s required, so our effect will become something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@Effect()
fetchDataWithDebounce$ = this.actions$
   .ofType(actions.DATA_WITH_DEBOUNCE_FETCH)
   .debounceTime(100, this.scheduler)
   *// Call API service or some other processing
   *.map(() =&gt; ({ type: actions.DATA_WITH_DEBOUNCE_FETCH_SUCCESS }));&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once that is done, we can pass the test scheduler when we create an instance of the effect inside the tests:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const scheduler = getTestScheduler();
const effect = new AppTimeEffect(new Actions(source), scheduler);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case we edited the effect code so we can test it, but our intent is more clear. On the good side, we still avoided using Angular specific constructs like the TestBed.&lt;/p&gt;
&lt;p&gt;If you want to know more about the future of schedulers in RxJs have a look at &lt;a href=&quot;https://github.com/ReactiveX/rxjs/issues/2935#issuecomment-336681001&quot;&gt;this thread&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Custom preloading strategy for Angular modules]]></title><description><![CDATA[Lets say we have a medium sized Angular application and each large feature split into a lazy loaded module. When the application starts, we load only the main modules and all the routes are lazy loaded, including the first one that we navigate to.]]></description><link>https://adrianfaciu.dev/posts/preloading-strategy/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/preloading-strategy/</guid><pubDate>Thu, 30 Nov 2017 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Lets say we have a medium sized Angular application and each large feature split into a lazy loaded module.&lt;/p&gt;
&lt;p&gt;When the application starts, we load only the main modules and all the routes are lazy loaded, including the first one that we navigate to:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist83581751&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-example_lazy_routes-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;example_lazy_routes.ts content, created by adrianfaciu on 08:12PM on November 29, 2017.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;example_lazy_routes.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const routes: Routes = [&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    { path: &amp;#39;&amp;#39;, redirectTo: &amp;#39;items&amp;#39;, pathMatch: &amp;#39;full&amp;#39; },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;items&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+items/items.module#ItemsModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;item&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+item-details/item-details.module#ItemDetailsModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;admin&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+admin/admin.module#AdminModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;];&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/78070c4409702e6e4c947150c00774d9/raw/1481c54b821f7e06ce19ce701e70522b750e881d/example_lazy_routes.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/78070c4409702e6e4c947150c00774d9#file-example_lazy_routes-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          example_lazy_routes.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;So what happens is that the app, core and shared modules are loaded, right away we navigate to a feature page and the coresponding module is loaded. When we go to item details page, since the module is lazy loaded, before we do something we have to wait for it to get loaded.&lt;/p&gt;
&lt;p&gt;This is already an awesome setup and thumbs up if you use it 👍&lt;/p&gt;
&lt;p&gt;We can improve things a bit by using a &lt;a href=&quot;https://angular.io/api/router/PreloadingStrategy&quot;&gt;preloading strategy&lt;/a&gt; that Angular provides for us. When we provide the routes to the &lt;a href=&quot;https://angular.io/api/router/RouterModule&quot;&gt;router module&lt;/a&gt; we have a second argument where we can specify a strategy.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;RouterModule.forRoot(routes, { preloadingStrategy: NoPreloading })&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Out of the box Angular provides two strategies already implemented for us, pretty explanatory from the name:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NoPreloading&lt;/strong&gt; — no modules are preloaded, this is the &lt;em&gt;default&lt;/em&gt; &lt;em&gt;behaviour&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PreloadAllModules&lt;/strong&gt; — all modules are preloaded as fast as possible&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While this will work in some scenarios, we might want to create something a bit more complex here. All we have to do is create a class that implements &lt;a href=&quot;https://angular.io/api/router/PreloadingStrategy&quot;&gt;PreloadingStrategy&lt;/a&gt; class.&lt;/p&gt;
&lt;p&gt;A good strategy here would be to load quickly just what is required and load some of the other modules with a small delay. We might know that after the initial load most of the users will go to a specific feature module, then after everything is loaded we can preload that feature module where we think users might go, or maybe preload all the other modules if we don’t have that many.&lt;/p&gt;
&lt;p&gt;We start by adding a data object to the routes config, so we can leverage this in our custom preloading strategy:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist83582005&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-example_lazy_routes_data-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;example_lazy_routes_data.ts content, created by adrianfaciu on 08:18PM on November 29, 2017.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;example_lazy_routes_data.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export const routes: Routes = [&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    { path: &amp;#39;&amp;#39;, redirectTo: &amp;#39;items&amp;#39;, pathMatch: &amp;#39;full&amp;#39; },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;items&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+items/items.module#ItemsModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        data: { preload: true, delay: false },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;item&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+item-details/item-details.module#ItemDetailsModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        data: { preload: true, delay: true },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        path: &amp;#39;admin&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        loadChildren: &amp;#39;app/+admin/admin.module#AdminModule&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        data: { preload: false, delay: true },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    },&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-example_lazy_routes_data-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;];&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/7d8c2180e1f4c1bdab54e48d823686ff/raw/0b71e5fbd1754c000867d5ecde4791ebc2fae10b/example_lazy_routes_data.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/7d8c2180e1f4c1bdab54e48d823686ff#file-example_lazy_routes_data-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          example_lazy_routes_data.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Inside the data object I’ve added two properties, both boolean:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;preload — if we want to preload that module or not&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;delay — if we want to load it right away or with a delay&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then we implement the preload method and decide which modules we preload right away and which we load with a small delay:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist83582074&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-app_preloading_strategy-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;app_preloading_strategy.ts content, created by adrianfaciu on 08:21PM on November 29, 2017.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;app_preloading_strategy.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class AppPreloadingStrategy implements PreloadingStrategy {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    preload(route: Route, load: Function): Observable&amp;lt;any&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const loadRoute = (delay) =&amp;gt; delay&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            ? timer(150).pipe(flatMap(_ =&amp;gt; load()))&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            : load();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        return route.data &amp;amp;&amp;amp; route.data.preload &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            ? loadRoute(route.data.delay)&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            : of(null);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;      }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-app_preloading_strategy-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/33fb44d7af5909d8dbfacd27c57352e3/raw/4a074cefed1d90994215cba9c375de97d0d4ce62/app_preloading_strategy.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/33fb44d7af5909d8dbfacd27c57352e3#file-app_preloading_strategy-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          app_preloading_strategy.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Normally we would just check to see if the route has the preload property set to true and then we would call the load function, if not we would return an observable with null value (this will indicate that we don’t want any preloading):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;return route.data &amp;amp;&amp;amp; route.data.preload ? load() : of(null);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This can be improved by creating a &lt;em&gt;loadRoute&lt;/em&gt; function that takes an argument, the delay property. If &lt;em&gt;delay is false&lt;/em&gt; we call the load function right away. If *delay is true *an observable that emits a value after an interval is created, with the timer method, and the result is flat mapped to calling the load method.&lt;/p&gt;
&lt;p&gt;The only thing left is to use this new strategy:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;RouterModule.forRoot(routes, {
   preloadingStrategy: AppPreloadingStrategy
})&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using this our module is already loaded when we need it and the user has an improved experience.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Use absolute paths for module imports]]></title><description><![CDATA[Handling imports is a bit more trickier to manage due to paths and constant refactoring that one will do inside a more complex application.]]></description><link>https://adrianfaciu.dev/posts/module-imports/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/module-imports/</guid><pubDate>Sat, 04 Nov 2017 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Handling imports is a bit more trickier to manage due to paths and constant refactoring that one will do inside a more complex application.&lt;/p&gt;
&lt;p&gt;When importing modules they are usually separated in two:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;importing libraries modules, which is quite nice, since we use only the name and they are resolved from &lt;em&gt;node_modules&lt;/em&gt; folder&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;importing modules from our own application&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When doing the second the web is, unfortunately, full of examples that use relative paths to get the needed file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { foo } from ‘../bar’;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is quite ok, but it goes quickly wrong when the file we need is several levels up or down. Then we get something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { foo } from ‘../../../../bar’;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which is hard to write/read and will break as soon as we move the file somewere else.&lt;/p&gt;
&lt;p&gt;Since &lt;strong&gt;TypeScript 2.0&lt;/strong&gt;, we have an awesome compiler setting called &lt;a href=&quot;https://github.com/Microsoft/TypeScript/wiki/What&amp;#x27;s-new-in-TypeScript#base-url&quot;&gt;&lt;strong&gt;baseUrl&lt;/strong&gt;&lt;/a&gt;, and we can configure it in the tsconfig.json file like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
  &quot;compilerOptions&quot;: {
    &quot;baseUrl&quot;: &quot;./src&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you are using &lt;a href=&quot;https://cli.angular.io&quot;&gt;&lt;em&gt;Angular CLI&lt;/em&gt;&lt;/a&gt; this will be already setup for you. In the tsconfig file for the app it’s set as above.&lt;/p&gt;
&lt;p&gt;Once this is done we can use a path starting from that base url, so most of our imports will be transformed to something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { foo } from ‘app/bar’&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I would use this for almost all of the imports throughout an application. Those that import from the same folder might be left as they are though.&lt;/p&gt;
&lt;p&gt;All our imports will be shorter to write, easy to understand and most important: &lt;strong&gt;will not break as we refactor and move files around&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With a few barrel files strategically placed we will have a very nice structure with imports that look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { UserService } from ‘app/core/services’;
import { SearchComponent } from ‘app/shared/components’;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to go a bit further there is also a setting for creating path mappings, but as of now, most editors and IDEs have some issues with correctly resolving this and in my opinion it is a bit harder to understand what is happening.&lt;/p&gt;
&lt;p&gt;It should be clear enough why this way of importing modules is a bit better and more error proof. We should all use this more when working on large application codebases.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Angular location service]]></title><description><![CDATA[There is a small and well hidden service inside Angular: the location service. As the name and documentation suggests, this is a class that is used to interact with the browser URL.]]></description><link>https://adrianfaciu.dev/posts/angular-location-service/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/angular-location-service/</guid><pubDate>Tue, 19 Sep 2017 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;There is a small and well hidden service inside Angular: &lt;a href=&quot;https://angular.io/api/common/Location&quot;&gt;the location service&lt;/a&gt;. As the name and documentation suggests, this is a class that is used to interact with the browser URL.&lt;/p&gt;
&lt;p&gt;I’ve seen people using this, probably by mistake, trying to navigate inside an application, this is not working because it’s not related to the router at all. We can use it to update/change the browser address, basically interacting with the URL outside of routing.&lt;/p&gt;
&lt;h3 id=&quot;use-case&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case&quot; aria-label=&quot;use case permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#use-case&quot; aria-label=&quot;use case permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use case&lt;/h3&gt;
&lt;p&gt;A nice place that I’ve found for this to use is to update the current location after we finish an operation that would normally change it, but we don’t want to involve the router (for example, to avoid any side effects and navigation triggers generated by a reload of the page).&lt;/p&gt;
&lt;p&gt;Lets say we have a route that goes to an item details, something like: ‘&lt;strong&gt;&lt;em&gt;item/{itemId}&lt;/em&gt;&lt;/strong&gt;’ and a very similar one that is used to create a new item: ‘&lt;strong&gt;&lt;em&gt;item/new&lt;/em&gt;&lt;/strong&gt;’.&lt;/p&gt;
&lt;p&gt;When we create a new item we navigate to the last one and the browser address is set to &lt;em&gt;item/new&lt;/em&gt;. After we add all the details when we send this to the API we get back the saved entity from the database, including the item id.&lt;/p&gt;
&lt;p&gt;Since the item was saved, we’re no longer in the new state, we’re in edit mode and we want to show this in the URL by changing &lt;strong&gt;&lt;em&gt;new&lt;/em&gt;&lt;/strong&gt; with ***id **value*.&lt;/p&gt;
&lt;p&gt;We could reload the page, but this will most probably fetch again the item from the API. And this in the most simple scenario, in more complex ones we can have multiple effects that are triggered when the page is loaded and we want to avoid all that extra stuff.&lt;/p&gt;
&lt;h3 id=&quot;solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solution&quot; aria-label=&quot;solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#solution&quot; aria-label=&quot;solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solution&lt;/h3&gt;
&lt;p&gt;Here comes to the rescue the location service. We can use the &lt;a href=&quot;https://angular.io/api/common/Location#go&quot;&gt;**go&lt;/a&gt;** method to update the address and to add it to the history, making sure that if we go to a different route and hit back button, we’ll end up with the item id in the address bar and not with new.&lt;/p&gt;
&lt;p&gt;Using the method is as simple as calling it with a string argument representing the new address:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/3b3eebe276173e286938064496d6c8a1&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;h3 id=&quot;code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code&quot; aria-label=&quot;code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#code&quot; aria-label=&quot;code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code&lt;/h3&gt;
&lt;p&gt;A sample, and very small, application that shows this can be found on &lt;a href=&quot;https://af-angular-location.stackblitz.io&quot;&gt;StackBlitz&lt;/a&gt;. If you want to edit the sample you can &lt;a href=&quot;https://stackblitz.com/edit/af-angular-location&quot;&gt;use this link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What other use cases did you find for the &lt;a href=&quot;https://angular.io/api/common/Location&quot;&gt;Location service&lt;/a&gt; ?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Testing NgRx effects]]></title><description><![CDATA[My approach in testing NgRx effects. Some of the things that worked and some that did not.]]></description><link>https://adrianfaciu.dev/posts/testing-ngrx/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/testing-ngrx/</guid><pubDate>Wed, 30 Aug 2017 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Since I’ve wrote this, both NgRx and RxJs released some new versions that require some small changes in how we can write the tests. You can see all those in &lt;a href=&quot;https://medium.com/@adrianfaciu/update-on-testing-ngrx-effects-cf32a80d3601&quot;&gt;this follow up&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you decide to use a &lt;em&gt;state management&lt;/em&gt; library in your &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; application (and for most of them you should :) ) a good choice is one of the &lt;a href=&quot;http://redux.js.org/&quot;&gt;Redux&lt;/a&gt; inspired libraries. You’ll most likely have actions, reducers and pretty soon something to handle all the side effects. In case of &lt;a href=&quot;https://github.com/ngrx/platform&quot;&gt;ngrx&lt;/a&gt;, these side effects are handled with the help of the ngrx/effects module.&lt;/p&gt;
&lt;p&gt;This post will show an approach on how to test &lt;a href=&quot;https://github.com/ngrx/platform&quot;&gt;ngrx effects&lt;/a&gt; and show some samples. It will not go into state management and why to use this library for managing side effects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An Effect&lt;/strong&gt; is a stream that filters the actions object (all the actions going through the application) and filters them based on the action type we want to react to. &lt;strong&gt;An action&lt;/strong&gt; is handled by a reducer function which updates the application state. In cases where we want to have some side effects (eg. xhr call) as a result of that action, we do it in an &lt;em&gt;Effect&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Testing reducers is pretty straight forward since they are pure functions and should not be that complex. The interesting part comes when we want to test the effects that we’ve built.&lt;/p&gt;
&lt;p&gt;There is some &lt;a href=&quot;https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md&quot;&gt;documentation &lt;/a&gt;and &lt;a href=&quot;https://github.com/ngrx/platform/tree/master/example-app/app/books/effects&quot;&gt;some samples&lt;/a&gt; on how to test them, but the samples don’t have that much information provided and they are using the &lt;a href=&quot;https://angular.io/api/core/testing/TestBed&quot;&gt;TestBed&lt;/a&gt; provided by Angular. I liked better the approach that &lt;a href=&quot;undefined&quot;&gt;Victor Savkin&lt;/a&gt; took in his &lt;a href=&quot;https://github.com/vsavkin/testing_ngrx_effects&quot;&gt;repo on how to test effects&lt;/a&gt;. We instantiate everything ourselves, there is no TestBed, no subscribe calls and generally the tests look and feel more clean.&lt;/p&gt;
&lt;p&gt;As a bonus this approach works with both old (2.x) and new (4.x) version of ngrx so you can easily have the tests up and running and then migrate with confidence, and without having to rewrite the tests afterwards.&lt;/p&gt;
&lt;p&gt;I’ve added some samples, including a bit more complex scenarios that I’ve encountered while writing tests for effects, and tried to explain each of them.&lt;/p&gt;
&lt;p&gt;We use &lt;a href=&quot;https://github.com/synapse-wireless-labs/jasmine-marbles&quot;&gt;jasmine-marbles&lt;/a&gt; for easier testing and a better visualisation of Observables. While it’s not wildly popular, it’s being used trough several open source projects (including ngrx itself) and quite a few presentations. The code base is quite small so you could look at it and implement it yourself if needed.&lt;/p&gt;
&lt;p&gt;Assuming we have the most simple effect possible that just listens for an action, might do some processing, and triggers another action as a result. The most basic approach would look something like:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/e9f16c1a8345268ada3581fa256dd10b&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;We listen to the increment action, perform any processing we might want to and generate a new action.&lt;/p&gt;
&lt;p&gt;Inside a test we would want to trigger the increment action and make sure we always get back the update text resulting action:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/7b3ab9a1ea06eed1933ebf26528f3649&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;Using jasmine-marbles library we can create observables using marble diagrams which generally helps a lot when reading the tests. So if we have an observable that emits two values we can describe it as: ‘ -a-b-|’.&lt;/p&gt;
&lt;p&gt;When using marble diagrams we represent them as a string using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;to represent passing of time (10 frames)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;| to mark the completion event&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h1 id=&quot;to-emit-an-error&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#to-emit-an-error&quot; aria-label=&quot;to emit an error permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#to-emit-an-error&quot; aria-label=&quot;to emit an error permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;to emit an error&lt;/h1&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;most other characters to represent an emitted value&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The library has two useful methods hot/cold that allow us to create an observable from a string representation. If you want to read about the difference between a cold and a hot observable, &lt;a href=&quot;undefined&quot;&gt;Ben Lesh&lt;/a&gt; has a &lt;a href=&quot;https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339&quot;&gt;great article about this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When we create an observable using hot/cold method, the second parameter that we can pass to the method is an object that maps values for each emitted item. In our case we only pass the action object that we want to handle:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*yTcOQhEC9oAWASV4q1LPng.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another nice thing that jasmine-marbles adds is the &lt;strong&gt;toBeObservable&lt;/strong&gt; matcher so we can directly compare our input with the expected result:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*fPgLaYIlFP6M1iu8IXSDJA.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is the basic setup for testing a simple effect that we might use.&lt;/p&gt;
&lt;p&gt;We can move on to our second testing scenario where we use a service in the effect and we want to mock it:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/3b92fe1f1eed50343dce16103290ee61&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;Similar to our first example just that in this case we’re using a service to fetch some data. We get this service through dependency injection so we’ll need to mock it in our test to make sure we don’t hit an API or some other costly operation.&lt;/p&gt;
&lt;p&gt;An important thing we should notice is that we don’t want to throw an exception directly on an effect stream, remember this is the main actions stream and an Observable is done after an error occured, so if we do that, no more actions will flow through the application. This is why we use the switchMap/catch combination and we make sure we create a test that checks this case.&lt;/p&gt;
&lt;p&gt;We create a mock for our service using *createSpyObject *method from jasmine and we handle both cases where we want to return a value or an error:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/5a50df233241c308e57771932de8ca0d&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;If we pass in a value, we return an observable that will emit that value and if we pass in an error object, we return an observable that will throw that error.&lt;/p&gt;
&lt;p&gt;Having this in place we can create our first test to check that we can retrieve data:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/74e0b5ef218c83d8b4b403bcaaf6e1e3&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;This looks pretty much as our first simple test, we instantiate a new service instance with our mock method and pass it in the effect constructor. Checking the expected value is pretty much as before. For simplicity we’re checking just the action type, but in a more real world application we would also check that the payload from the action contains the data that we want.&lt;/p&gt;
&lt;p&gt;As mentioned above, we need to make sure we handle an exception on the stream, so we also test that our catch method works as it should:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/fbb17b594153be5ca03a7cd81874108a&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;In this case we create our service and pass an error so when we call *getDummyData *it will emit the error and it should be caught and transformed in a data fetch failed action.&lt;/p&gt;
&lt;p&gt;Another type of effect that we can have is where we might need some other data from our application state in order to process the action or to generate a new one. This would be simple if the data would be in the same part, handled by the same reducer, but imagine that we have a more complex state object and we need to fetch something from different places. An option is to inject the store in the effect class and select what we need:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/5010322f7e6490bf288d5947bb6e210b&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;Notice that we’re creating two streams *numberStream *and *textStream *that read some data from the state and then use these values in the effect, in the *withLatestFrom *operator.&lt;/p&gt;
&lt;p&gt;In order to test this effect we need to mock the store and make sure we select whatever data we want from it. If we would have only one stream we could have easily mocked the store and return whatever we want:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*cXyWqtGOn7UgEVOMxy2wpQ.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;But if we have multiple streams for which we use different selector it will be more tricky. One nice way to handle this is to actually initialize the state with the default value by calling the root reducer with an unknown ‘INIT’ action. Then we can call the selector on the state object and return the result in a stream:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*Dv6i_qweIkX8Tkoh4w1BlA.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The whole test looks like this:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/96743b8a53b29c4fcb25c840a211db39&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;The last type of test that I’ve encountered is that where we need to control time :) If we use different kind of operators like &lt;em&gt;timer&lt;/em&gt;, *interval *or &lt;em&gt;debounceTime&lt;/em&gt; on our effects we need some special handling in our tests.&lt;/p&gt;
&lt;p&gt;Suppose we have an effect that looks like this:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/faf2203b2e0c612e7e5d28db920ff9d8&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;We can see that we use &lt;em&gt;debounceTime&lt;/em&gt; operator to emit only the last value from a period of time and ignore the rest. Since we do this our normal way to test this will not work, since when we check the expected value the initial one will not have emitted anything.&lt;/p&gt;
&lt;p&gt;One dirty way to hack around this is to spy on the operator and make it do nothing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*IW_oRloVJMwWd6G3WMtrsQ.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Basically we just return the stream itself without anything applied to it, and then we can write the test as we would normally do, just make sure to spy on the observable operator before we create the effect:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/8b53f601410065117f359628cf9a53dc&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;A second approach is to use the Scheduler that is provided by the jasmine marbles library. If you look in the ngrx repository at &lt;a href=&quot;https://github.com/ngrx/platform/blob/master/example-app/app/books/effects/book.ts&quot;&gt;the sample app&lt;/a&gt; you can see that an optional injected scheduler is used inside the effects class. If it’s provided it’s used, if not, the default one from rxjs is used.&lt;/p&gt;
&lt;p&gt;While this approach works just fine, it makes you add some code in all the effect classes that is not used for anything else beside testing. Another thing is that you’ll have to instantiate the effect using the TestBed provided by Angular to make sure that everything is in place.&lt;/p&gt;
&lt;p&gt;A different approach, using the same scheduler that you can fetch using *getTestScheduler *method, is to override all the required Observable operators to use it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*xfCSAYrsuqnHP12P2mic5g.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A similar approach to what we used in the first try, here we just save the original operator and call it with our scheduler.&lt;/p&gt;
&lt;p&gt;This will make sure our test passes again, as long as we spy on the operator before we instantiate the effect class:&lt;/p&gt;
&lt;iframe src=&quot;https://medium.com/media/12ab1c1467c20b510c3b7d1d8dc851ed&quot; frameborder=0&gt;&lt;/iframe&gt;
&lt;p&gt;So far these have been the most common scenarios that I’ve encountered while writing tests for ngrx effects.&lt;/p&gt;
&lt;p&gt;You can find the complete &lt;a href=&quot;https://github.com/adrianfaciu/testingNgRx&quot;&gt;working code on GitHub&lt;/a&gt;. Have fun writing tests ;)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Creating a Mobile App for a Smart Light Bulb with NativeScript & Angular]]></title><description><![CDATA[Since one of the awesome things I got from AngularConnect was a Magic Blue smart light bulb and NativeScript looks like an interesting framework, I’ve decided to create a small mobile app to interact with it.]]></description><link>https://adrianfaciu.dev/posts/smart-light-bulb/</link><guid isPermaLink="false">https://adrianfaciu.dev/posts/smart-light-bulb/</guid><pubDate>Thu, 06 Oct 2016 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Since one of the awesome things I got from AngularConnect was a Magic Blue smart light bulb and NativeScript looks like an interesting framework, I’ve decided to create a small mobile app to interact with it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.nativescript.org&quot;&gt;NativeScript &lt;/a&gt;is an open source framework for building native mobile applications, using web technologies, and it works with the latest version of &lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/nativescript-1.jpeg&quot; alt=&quot;smart light bulb&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’ll go through setting up the environment, creating a new template application, a basic component and interacting with the light bulb.&lt;/p&gt;
&lt;h3 id=&quot;environment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#environment&quot; aria-label=&quot;environment permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#environment&quot; aria-label=&quot;environment permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Environment&lt;/h3&gt;
&lt;p&gt;First you need to setup everything, before we actually get to write any code. You start with Node.js, which if you don’t have already you can go to &lt;a href=&quot;https://nodejs.org/&quot;&gt;nodejs.org&lt;/a&gt; and grab it.&lt;/p&gt;
&lt;p&gt;Second you need to install the NativeScript CLI:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install -g nativescript&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since it will build native Android or iOS apps you also need to setup the platform for each of them, things like Android SDK, Xcode, etc. I suggest you manually set them up, or you can go to the &lt;a href=&quot;http://docs.nativescript.org/start/quick-setup&quot;&gt;quick setup part in the NativeScript docs&lt;/a&gt; which have some ready made scripts that should do everything.&lt;/p&gt;
&lt;p&gt;Finally you can check that everything works using the NativeScript CLI doctor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns doctor&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run into trouble or want more information about the setup, the &lt;a href=&quot;http://docs.nativescript.org/start/quick-setup&quot;&gt;official docs&lt;/a&gt; are quite helpful.&lt;/p&gt;
&lt;h3 id=&quot;new-application&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#new-application&quot; aria-label=&quot;new application permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#new-application&quot; aria-label=&quot;new application permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;New application&lt;/h3&gt;
&lt;p&gt;Creating a new application is easy enough, with the help of NativeScript CLI. Create a new application template with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns create NativeScriptLightBulb --ng&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first parameter is the application name, and with the second one you’re specifying that we want to use Angular. You can also create applications without Angular, and they will use JavaScript/TypeScript only with the provided SDK.&lt;/p&gt;
&lt;p&gt;Second you need to add a new platform to the application, iOS or Android:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns platform add ios

tns platform add android&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point you can build and start the application in the emulator or on a real connected device:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns run android --emulator&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or, if you want to have a live sync kind of flow:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns livesync android --emulator --watch&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will watch all the files in the solution, build and redeploy the application on each change. Similar to modern web development workflows.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-first-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-the-first-component&quot; aria-label=&quot;creating the first component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#creating-the-first-component&quot; aria-label=&quot;creating the first component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating the first component&lt;/h3&gt;
&lt;p&gt;You can start by creating a simple Angular component, with the accompanying template and style files. For a better project structure add all of them into a &lt;em&gt;components/bulb-control&lt;/em&gt; folder.&lt;/p&gt;
&lt;p&gt;The project structure should look similar to this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/nativescript-2.png&quot; alt=&quot;sample project structure&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then create a class and add the component decorator:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40556931&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-bulb-control-component-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;bulb-control.component.ts content, created by adrianfaciu on 07:30PM on October 03, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;bulb-control.component.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;import { Component } from &amp;#39;@angular/core&amp;#39;;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;@Component({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    moduleId: module.id,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    selector: &amp;#39;ns-bulb-control&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    templateUrl: &amp;#39;bulb-control.component.html&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    styleUrls: [&amp;#39;bulb-control.component.css&amp;#39;]&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;})&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class BulbControlComponent {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    maxValue = 255;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    minValue = 0;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    redValue = 128;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    greenValue = 0;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    blueValue = 0;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    whiteValue = 0;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    updateLightBulb() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        console.log(&amp;#39;Update color&amp;#39;);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L21&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L22&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    connectToMagicBlue() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L23&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        console.log(&amp;#39;Connecting to device&amp;#39;);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L24&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;24&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC24&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-L25&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;25&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-ts-LC25&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/8fa74249a8e2f9c2b288a9272c4b8223/raw/b8a3167a36021f8b2a9efc1b13561f7b32578588/bulb-control.component.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/8fa74249a8e2f9c2b288a9272c4b8223#file-bulb-control-component-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          bulb-control.component.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Beside the boilerplate code, there is one method that will eventually update the light bulb color, a method to connect to the light bulb, a set of properties that will be used to bind the color model (red, green, blue, warm white) and some minimum and maximum values for a color. I’ll create the template for this model shortly.&lt;/p&gt;
&lt;p&gt;NativeScript uses Angular, but it doesn’t work with a browser, so you won’t be able to use elements like *div *or *h1. *Instead NativeScript provides us a &lt;a href=&quot;http://docs.nativescript.org/ui/components&quot;&gt;custom made collection of elements&lt;/a&gt; that one can use, and each of these elements will be translated into a native Android or iOS UI component.&lt;/p&gt;
&lt;p&gt;Adding some basic controls for a simple UI, that can be used to control the color of the light bulb, is all that’s needed.&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40557484&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-bulb-control-component-html&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-html  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;bulb-control.component.html content, created by adrianfaciu on 07:50PM on October 03, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;bulb-control.component.html&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;StackLayout&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Label text=&amp;quot;Magic Blue&amp;quot;&amp;gt;&amp;lt;/Label&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Button (tap)=&amp;quot;connectToMagicBlue()&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            text=&amp;quot;Connect&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Button&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Slider [minValue]=&amp;quot;minValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [maxValue]=&amp;quot;maxValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [(ngModel)]=&amp;quot;redValue&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Slider&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Slider [minValue]=&amp;quot;minValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [maxValue]=&amp;quot;maxValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [(ngModel)]=&amp;quot;greenValue&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Slider&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Slider [minValue]=&amp;quot;minValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [maxValue]=&amp;quot;maxValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [(ngModel)]=&amp;quot;blueValue&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Slider&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L18&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Slider [minValue]=&amp;quot;minValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L19&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [maxValue]=&amp;quot;maxValue&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L20&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            [(ngModel)]=&amp;quot;whiteValue&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L21&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Slider&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L22&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;Button (tap)=&amp;quot;updateLightBulb()&amp;quot; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L23&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            text=&amp;quot;Apply&amp;quot;&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L24&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;24&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC24&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &amp;lt;/Button&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-bulb-control-component-html-L25&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;25&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-bulb-control-component-html-LC25&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;StackLayout&amp;gt;&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/94c5311a817d1315de5530a54628e872/raw/3105a547f444472558a8ff85da9da8a4a4362400/bulb-control.component.html&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/94c5311a817d1315de5530a54628e872#file-bulb-control-component-html&quot; class=&quot;Link--inTextBlock&quot;&gt;
          bulb-control.component.html
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;First you specify the stack layout, and then added two buttons, one for each of our actions, four sliders for the color model and a title so you know what the application does :)&lt;/p&gt;
&lt;p&gt;The Angular binding syntax work here also, so you can add event handlers with *(tap)=”updateLightBulb()”, *bind to element properties with *[minValue]=”minValue” *and use two way binding with [(ngModel)]=”blueValue”. &lt;a href=&quot;https://angular.io/docs/ts/latest/guide/template-syntax.html&quot;&gt;Angular documentation&lt;/a&gt; offers more insights about this if needed.&lt;/p&gt;
&lt;p&gt;With some basic styling (can be grabbed &lt;a href=&quot;https://github.com/adrianfaciu/NativeScriptLightBulb/tree/master/app/components/bulb-control&quot;&gt;from GitHub&lt;/a&gt;) the application should look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/nativescript-3.png&quot; alt=&quot;screenshot from a real device&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;interacting-with-the-light-bulb&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interacting-with-the-light-bulb&quot; aria-label=&quot;interacting with the light bulb permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#interacting-with-the-light-bulb&quot; aria-label=&quot;interacting with the light bulb permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interacting with the light bulb&lt;/h3&gt;
&lt;p&gt;Even though NativeScript offers the option to &lt;a href=&quot;http://docs.nativescript.org/angular/tutorial/ng-chapter-6&quot;&gt;access all native APIs directly&lt;/a&gt; from TypeScript, which is pretty neat, I’ll use a ready made plugin that will interact with bluetooth connectivity.&lt;/p&gt;
&lt;p&gt;NativeScript-Bluetooth can be found on &lt;a href=&quot;https://github.com/EddyVerbruggen/nativescript-bluetooth&quot;&gt;GitHub&lt;/a&gt; and you can add it to the project using the CLI:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tns plugin add nativescript-bluetooth&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, you can move on, to create some services to help interact with the bluetooth plugin. You can create one as a wrapper for the bluetooth plugin and one to hold the logic related to the light bulb.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;posts/nativescript-4.png&quot; alt=&quot;solution opened in visual studio code&quot;&gt;&lt;/p&gt;
&lt;p&gt;A class to hold a bluetooth device properties might come in handy also.&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40558128&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-ble-device-model-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;ble-device.model.ts content, created by adrianfaciu on 08:14PM on October 03, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;ble-device.model.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-ble-device-model-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-ble-device-model-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;export class BleDevice {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-ble-device-model-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-ble-device-model-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    constructor(public UUID: string, &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-ble-device-model-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-ble-device-model-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                public name: string, &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-ble-device-model-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-ble-device-model-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                public state: string) { }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-ble-device-model-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-ble-device-model-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/f6f349697ea833b7f9ad001ec002025c/raw/59e696336fd3244f1b6d392c1a9ab6adf6e29697/ble-device.model.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/f6f349697ea833b7f9ad001ec002025c#file-ble-device-model-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          ble-device.model.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;First thing that you need to do is handle the application permissions. For Android this means that inside the AndroidManifest.xml file you’ll add these extra three permissions:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;uses-permission android:name=”android.permission.BLUETOOTH”/&gt;
&amp;lt;uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”/&gt;&amp;lt;uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first two will allow to discover and connect to bluetooth devices, and the last one is needed to access the device location. This is needed for devices running Android 6, where you need the location permission in order to scan for nearby BLE enabled devices.&lt;/p&gt;
&lt;p&gt;Moreover, even if they are added, you need an extra step to request for permission at run time in order to be able to scan for devices. You can do this with *requestCoarseLocationPermission *method from the bluetooth plugin:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40625235&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-fix-permission-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;fix-permission.ts content, created by adrianfaciu on 08:18PM on October 05, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;fix-permission.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    fixPermission(): void {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        bluetooth.hasCoarseLocationPermission()&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            .then((granted) =&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                if (!granted) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                    bluetooth.requestCoarseLocationPermission()&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                        .then(() =&amp;gt; console.log(&amp;quot;Location permission requested&amp;quot;));&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            });&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-fix-permission-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-fix-permission-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/5352ddb279295bd2d7b627bc2053acb6/raw/85d891f030b986e300bb77026b1b70f06065a6f4/fix-permission.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/5352ddb279295bd2d7b627bc2053acb6#file-fix-permission-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          fix-permission.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;You can call this method when the application initialises, to be sure we have the permission from that point on. For example in the OnInit hook of our light bulb component.&lt;/p&gt;
&lt;p&gt;Other methods like &lt;em&gt;write&lt;/em&gt;, *connect *or *disconnect *from the bluetooth service are just wrappers around the ones from the bluetooth plugin so I could add callbacks with some log messages. You could have, just as easily, used directly methods from the plugin. As a bonus you get an abstraction, the application does not know directly of this plugin, and you could switch it with something else, or with my own implementation by changing only this service.&lt;/p&gt;
&lt;p&gt;The last interesting method here is *scan, *where you try to fetch all the devices available and store them:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40625357&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-scan-devices-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;scan-devices.ts content, created by adrianfaciu on 08:22PM on October 05, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;scan-devices.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    scan(): Promise&amp;lt;any&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        return bluetooth.startScanning({&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            serviceUUIDs: [],&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            seconds: 3,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            onDiscovered: (device) =&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                const bleDevice = new BleDevice(device.UUID, device.name, device.state);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                this.bleDevicesAround.push(bleDevice);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        });&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-scan-devices-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-scan-devices-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/89f3b2cf870782322202de4dab6336f6/raw/5a76e1c6c9676cc97222c4e03ebd8c86a2eae3c9/scan-devices.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/89f3b2cf870782322202de4dab6336f6#file-scan-devices-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          scan-devices.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;You’ll use the devices list further on when you’ll try to figure out which one is a smart light bulb.&lt;/p&gt;
&lt;h3 id=&quot;hooking-up-the-ui-and-the-light-bulb&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hooking-up-the-ui-and-the-light-bulb&quot; aria-label=&quot;hooking up the ui and the light bulb permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#hooking-up-the-ui-and-the-light-bulb&quot; aria-label=&quot;hooking up the ui and the light bulb permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hooking up the UI and the light bulb&lt;/h3&gt;
&lt;p&gt;Use the light bulb command service to interact with the device from the UI components. There will be two essential methods in here, one to figure out which of the devices is magic blue and one to write a message to the light bulb in order to change its color.&lt;/p&gt;
&lt;p&gt;A naive approach for detecting the device and just fetch the fist one that has ‘&lt;em&gt;LEDBLE&lt;/em&gt;’ in its name works great. After that you need to connect to it, so it will be ready for receiving messages:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40625828&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-connect-magic-blue-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;connect-magic-blue.ts content, created by adrianfaciu on 08:40PM on October 05, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;connect-magic-blue.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    getMagicBlue(): BleDevice {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        return this.bluetoothService.bleDevicesAround&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            .filter(d =&amp;gt; d.name &amp;amp;&amp;amp; d.name.indexOf(&amp;#39;LEDBLE&amp;#39;) &amp;gt; -1)[0];&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    connectToMagicBlue() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.bluetoothService.scan().then(() =&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            this.magicBlue = this.getMagicBlue();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            if (this.magicBlue) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                this.bluetoothService.connect(this.magicBlue.UUID)&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;                    .then((device) =&amp;gt; console.log(&amp;#39;Connected: &amp;#39; + JSON.stringify(device)));&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        });&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-connect-magic-blue-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/d54e9f4f365b92bffede4dbfff19d0a4/raw/736b294b4ea25339e3fd00f5b8c4017357ace776/connect-magic-blue.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/d54e9f4f365b92bffede4dbfff19d0a4#file-connect-magic-blue-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          connect-magic-blue.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The second important part here is actually sending a message to the device. Nothing to complicated here, you need to create a message with the correct structure and add data with the correct encoding. Had quite a lot of fun trying to figure out what the light bulb expects but managed to figure it out in the end:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40625910&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-send-message-to-magic-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;send-message-to-magic.ts content, created by adrianfaciu on 08:43PM on October 05, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;send-message-to-magic.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    update(red: number, green: number, blue: number, white: number) {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const color = [86, red, green, blue, white, 240, 170].map(param =&amp;gt; {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            return this.convertToHexString(param);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        }).join(&amp;quot;,&amp;quot;);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        const updateMessage = this.getMessage(this.magicBlue.UUID, color);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.bluetoothService.write(updateMessage);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    getMessage(UUID: string, value: string): any {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L11&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        return {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L12&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            peripheralUUID: UUID,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L13&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            serviceUUID: &amp;#39;ffe5&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L14&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            characteristicUUID: &amp;#39;ffe9&amp;#39;,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L15&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            value: value&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L16&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        };&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-L17&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-send-message-to-magic-ts-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/14a2bcadbfdc8dc669801ecd66193f82/raw/4f3bca70d4240d95c65e59562c5aa50cec41f5e2/send-message-to-magic.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/14a2bcadbfdc8dc669801ecd66193f82#file-send-message-to-magic-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          send-message-to-magic.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The message structure is composed from the device identifier and value to be written along with the service and characteristic ids of the device. This is device specific and is retrieved in the *connect &lt;em&gt;method&lt;/em&gt;. *Each device can have multiple services with multiple characteristics. Each of them has a set of properties, and if &lt;em&gt;write&lt;/em&gt; is specified as true, it means you can write values to it.&lt;/p&gt;
&lt;p&gt;The data that you need to write to the light bulb is formed from the RGB colors, along with some (in this case) hard coded values that control other properties of the light bulb. The bluetooth plugin expects data in hexadecimal so we map all elements of the array to that and join them.&lt;/p&gt;
&lt;p&gt;Having this done, you can go back to the component and wire up the connect and update methods in there:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist40626373&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot; data-color-mode=&quot;light&quot; data-light-theme=&quot;light&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        
&lt;div class=&quot;js-gist-file-update-container js-task-list-container&quot;&gt;
      &lt;div id=&quot;file-light-bulb-component-updated-ts&quot; class=&quot;file my-2&quot;&gt;
    
    &lt;div itemprop=&quot;text&quot;
      class=&quot;Box-body p-0 blob-wrapper data type-typescript  &quot;
      style=&quot;overflow: auto&quot; tabindex=&quot;0&quot; role=&quot;region&quot;
      aria-label=&quot;light-bulb-component-updated.ts content, created by adrianfaciu on 09:01PM on October 05, 2016.&quot;
    &gt;

        
&lt;div class=&quot;js-check-hidden-unicode js-blob-code-container blob-code-content&quot;&gt;

  &lt;template class=&quot;js-file-alert-template&quot;&gt;
  &lt;div data-view-component=&quot;true&quot; class=&quot;flash flash-warn flash-full d-flex flex-items-center&quot;&gt;
  &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
    &lt;span&gt;
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.co/hiddenchars&quot; target=&quot;_blank&quot;&gt;Learn more about bidirectional Unicode characters&lt;/a&gt;
    &lt;/span&gt;


  &lt;div data-view-component=&quot;true&quot; class=&quot;flash-action&quot;&gt;        &lt;a href=&quot;{{ revealButtonHref }}&quot; data-view-component=&quot;true&quot; class=&quot;btn-sm btn&quot;&gt;    Show hidden characters
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/template&gt;
&lt;template class=&quot;js-line-alert-template&quot;&gt;
  &lt;span aria-label=&quot;This line has hidden Unicode characters&quot; data-view-component=&quot;true&quot; class=&quot;line-alert tooltipped tooltipped-e&quot;&gt;
    &lt;svg aria-hidden=&quot;true&quot; data-component=&quot;Octicon&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; data-view-component=&quot;true&quot; class=&quot;octicon octicon-alert&quot;&gt;
    &lt;path d=&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;/span&gt;&lt;/template&gt;

  &lt;table data-hpc class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;4&quot; data-paste-markdown-skip data-tagsearch-path=&quot;light-bulb-component-updated.ts&quot;&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L1&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    connectToMagicBlue() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L2&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.lightBulbCommandService.connectToMagicBlue();&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L3&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L4&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L5&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    updateLightBulb() {&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L6&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;        this.lightBulbCommandService.update(this.redValue,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L7&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            this.greenValue,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L8&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            this.blueValue,&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L9&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;            this.whiteValue);&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-L10&quot; class=&quot;blob-num js-line-number js-blob-rnum&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
          &lt;td id=&quot;file-light-bulb-component-updated-ts-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    }&lt;/td&gt;
        &lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;


    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/356bda602fc0761df41bd4c98bb58e1b/raw/c8e774e547c30825ce0383c412d6ea317964a9cd/light-bulb-component-updated.ts&quot; style=&quot;float:right&quot; class=&quot;Link--inTextBlock&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/adrianfaciu/356bda602fc0761df41bd4c98bb58e1b#file-light-bulb-component-updated-ts&quot; class=&quot;Link--inTextBlock&quot;&gt;
          light-bulb-component-updated.ts
        &lt;/a&gt;
        hosted with &amp;#10084; by &lt;a class=&quot;Link--inTextBlock&quot; href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;And voilà, you’re controlling the light color :)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/posts/nativescript-5.png&quot; alt=&quot;screenshot of app running&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;source-code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#source-code&quot; aria-label=&quot;source code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;#source-code&quot; aria-label=&quot;source code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Source code&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/adrianfaciu/NativeScriptLightBulb&quot;&gt;complete source code&lt;/a&gt; can be found in &lt;a href=&quot;https://github.com/adrianfaciu/NativeScriptLightBulb&quot;&gt;this GitHub repository&lt;/a&gt;. It contains a full working solution and some small updates beside what was described above. Have fun coding!&lt;/p&gt;</content:encoded></item></channel></rss>