<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: George Knap</title>
    <description>The latest articles on DEV Community by George Knap (@georgeknap).</description>
    <link>https://dev.to/georgeknap</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1097040%2F0501b390-9275-4db6-bf9f-e70f1511bbd7.jpeg</url>
      <title>DEV Community: George Knap</title>
      <link>https://dev.to/georgeknap</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/georgeknap"/>
    <language>en</language>
    <item>
      <title>The catch in the RxJS catchError</title>
      <dc:creator>George Knap</dc:creator>
      <pubDate>Fri, 09 Jun 2023 05:01:04 +0000</pubDate>
      <link>https://dev.to/georgeknap/the-catch-in-the-rxjs-catcherror-51mp</link>
      <guid>https://dev.to/georgeknap/the-catch-in-the-rxjs-catcherror-51mp</guid>
      <description>&lt;p&gt;Hi friends, George here.&lt;/p&gt;

&lt;p&gt;Catching errors in rxjs streams can be troublesome.&lt;/p&gt;

&lt;p&gt;Let's explain 3 different options and outcomes for our demo use case:&lt;br&gt;
Let's imagine we have a component that fetch data for different entities from the database. Fetch requests come in time in a form of rxjs stream - for our case let us mock it with rxjs interval&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const interval$ = interval(1000).pipe(skip(1));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, we have an API service which is responsible for getting a data. However, our API is not reliable and from time to time throws an error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable(
  providedIn: 'root',
})
export class DemoService {
  /**
   * mock of an api endpoint which throws an error on each even call
   */
  getData(counter: number): Observable&amp;lt;any&amp;gt; {
    if (counter % 2 === 0) {
      return throwError(() =&amp;gt; new Error());
    }


    return of(`some demo data ${counter}`);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's get the data from the API service in ngOnInit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ngOnInit() {
    const interval$ = interval(1000).pipe(skip(1));


    this.data$ = interval$.pipe(
      tap((i) =&amp;gt; console.log(i)),
      switchMap((i) =&amp;gt; this.demoService.getData(i)),
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, how do we handle these errors incoming from the API?&lt;/p&gt;

&lt;h2&gt;
  
  
  1. catchError and returning new observable
&lt;/h2&gt;

&lt;p&gt;In my team this is what we have done many time without thinking it through&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.data$ = interval$.pipe(
      switchMap((i) =&amp;gt; this.demoService.getData(i)),
      catchError(() =&amp;gt; of('error is cought from api'))
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we did not realize is that we are re-emitting new observable - the one created by of() function and the data$ will subscribe to it. Hence returning the caught value and completing the stream.&lt;br&gt;
This is what happens&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; 1
&amp;gt; 2 //cought

streamed was unsubscribed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. catchError while returning the cought observable
&lt;/h2&gt;

&lt;p&gt;If you look at the &lt;a href="https://rxjs.dev/api/operators/catchError"&gt;catchError&lt;/a&gt; documentation you can see the callback actually takes two parameters: error itself and the cought observable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;catchError&amp;lt;T, O extends ObservableInput&amp;lt;any&amp;gt;&amp;gt;(selector: (err: any, caught: Observable&amp;lt;T&amp;gt;) =&amp;gt; O): OperatorFunction&amp;lt;T, T | ObservedValueOf&amp;lt;O&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can use this to re-emit the original observable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.data$ = interval$.pipe(
      switchMap((i) =&amp;gt; this.demoService.getData(i)),
      catchError((err, cought$) =&amp;gt; cought$)
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this way the stream will start emitting values again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; 1
&amp;gt; 2//cought
&amp;gt; 1
&amp;gt; 2//cought
&amp;gt; 1
&amp;gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. catchError inside service stream
&lt;/h2&gt;

&lt;p&gt;In order to continue the original stream with new incoming values we have to move the catch to the inner observable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    this.data$ = interval$.pipe (
      switchMap((i) =&amp;gt;
        this.demoService.getData(i).pipe(catchError(() =&amp;gt; of('cought')))
      )
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this way we get a stream with cought values&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; 1
&amp;gt; 2 //cought
&amp;gt; 3
&amp;gt; 4 //cought
&amp;gt; 5
&amp;gt; 6 //cought
&amp;gt; 7
&amp;gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're lazy like me feel free to see the demo in &lt;a href="https://stackblitz.com/edit/angular-ivy-clgh9e?file=src%2Fapp%2Fapp.component.ts"&gt;Stackblitz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy catching!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>takeUntilDestroyed() - How I got disappointed</title>
      <dc:creator>George Knap</dc:creator>
      <pubDate>Thu, 08 Jun 2023 16:44:45 +0000</pubDate>
      <link>https://dev.to/georgeknap/takeuntildestroyed-how-i-got-disappointed-ep0</link>
      <guid>https://dev.to/georgeknap/takeuntildestroyed-how-i-got-disappointed-ep0</guid>
      <description>&lt;p&gt;Hi Friends, George here.&lt;/p&gt;

&lt;p&gt;It was a big surprise for me - takeUntilDestroyed - finally something natively supported by Angular coming to version 16.&lt;/p&gt;

&lt;p&gt;When it arrived I was disapponted. Why?&lt;br&gt;
Well let's say I was hoping for something more seamless to use.&lt;/p&gt;

&lt;p&gt;Let's have a look at how this new pipe is implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function takeUntilDestroyed&amp;lt;T&amp;gt;(destroyRef?: DestroyRef): MonoTypeOperatorFunction&amp;lt;T&amp;gt; {
  if (!destroyRef) {
    assertInInjectionContext(takeUntilDestroyed);
    destroyRef = inject(DestroyRef);
  }

  const destroyed$ = new Observable&amp;lt;void&amp;gt;(observer =&amp;gt; {
    const unregisterFn = destroyRef!.onDestroy(observer.next.bind(observer));
    return unregisterFn;
  });

  return &amp;lt;T&amp;gt;(source: Observable&amp;lt;T&amp;gt;) =&amp;gt; {
    return source.pipe(takeUntil(destroyed$));
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is that weird destroyRef parameter?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DestroyRef&lt;/code&gt; is an injectable token which can take a callback &lt;code&gt;onDestroy&lt;/code&gt; and this callback will be executed right before it's scope is destroyed. Angular needs this reference object to know when the to clean up your sbscription.&lt;/p&gt;

&lt;p&gt;And that's the little annoying thing about this pipe. It's not magic! It doesn't work by itself! It always needs to have this destroyRef object.&lt;/p&gt;

&lt;p&gt;How does it get it? There are two ways you can see in the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; if (!destroyRef) {
    assertInInjectionContext(takeUntilDestroyed);
    destroyRef = inject(DestroyRef);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You can provide &lt;code&gt;destroyRef&lt;/code&gt; manually as a pipe parameter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can let Angular to inject it by itself&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This second option seems easy, right? No, because you need to be &lt;em&gt;in&lt;/em&gt; the injection context.&lt;/p&gt;

&lt;p&gt;Wait a sec, don't we have injection context everywhere?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's where injection context works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inject() must be called from an injection context 
such as a constructor, a factory function, a field initializer, 
or a function used with `runInInjectionContext`. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get it?&lt;br&gt;
You want to subscribe to an observable in &lt;code&gt;ngOnInit&lt;/code&gt; and use &lt;code&gt;takeUntilDestroyed&lt;/code&gt; to handle unsubscribe? Tough luck! You're not in the injection context.&lt;/p&gt;

&lt;p&gt;How do we do it then?&lt;/p&gt;

&lt;p&gt;We do it by injecting &lt;code&gt;destroyRef&lt;/code&gt; in the injection context and passing it as a parameter to the pipe.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyComponent {
  destroyRef = inject(DestroyRef);
  ngOnInit() {
    timer(0, 1000).pipe(takeUntilDestroyed(this.destroyRef)).subscribe(n =&amp;gt; console.log('timer', n));
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here we are. The amount of code to do it is now quite similar to well known method of declaring an unsubscribe subject by yourself.&lt;/p&gt;

&lt;p&gt;As we see this is not magic solution to all world's problems. In fact we should still keep in mind to try not to subscribe manually. &lt;/p&gt;

&lt;p&gt;I was really looking forward to a future to discard our typescript mixin that handles unsubscribe logic inside a base class that you have to extend if needed. I might share it with you in another post so stay tuned.&lt;/p&gt;

&lt;p&gt;Enjoy coding&lt;/p&gt;

&lt;p&gt;To learn more about DestroyRef provider I highly recommend this video from Dmytro on &lt;a href="https://www.youtube.com/watch?v=ga-MU1sb-Oo"&gt;Decoded Fronted Youtube channel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Dark/Light mode for apps based on Windows system theme as a keyboard shortcut</title>
      <dc:creator>George Knap</dc:creator>
      <pubDate>Wed, 07 Jun 2023 09:06:10 +0000</pubDate>
      <link>https://dev.to/georgeknap/darklight-mode-for-apps-as-a-keyboard-shortcut-231n</link>
      <guid>https://dev.to/georgeknap/darklight-mode-for-apps-as-a-keyboard-shortcut-231n</guid>
      <description>&lt;p&gt;Hi friends, George here.&lt;/p&gt;

&lt;p&gt;Have you ever taken your laptop from your dark programmer's office to a sunny rooftop to enjoy some fresh air, grab a beer and do some work?&lt;/p&gt;

&lt;p&gt;Sure George, sounds like a great idea however, I can't see anything  on my screen on that sunny rooftop!&lt;/p&gt;

&lt;p&gt;Well, could the problem be that you have a dark mode active in all your apps? What if there was a way to quickly toggle system settings to light mode and all the apps will adjust their themes?&lt;/p&gt;

&lt;p&gt;That exactly is what we are going to do!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;create a PowerShell script .ps1 file with following code (thanks chatGPT!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$RegKeyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
$AppsUseLightTheme = Get-ItemProperty -Path $RegKeyPath -Name "AppsUseLightTheme"
$SystemUsesLightTheme = Get-ItemProperty -Path $RegKeyPath -Name "SystemUsesLightTheme"
if ($AppsUseLightTheme.AppsUseLightTheme -eq 1 -and $SystemUsesLightTheme.SystemUsesLightTheme -eq 1) {
Set-ItemProperty -Path $RegKeyPath -Name "AppsUseLightTheme" -Value 0
Set-ItemProperty -Path $RegKeyPath -Name "SystemUsesLightTheme" -Value 0
} else {
Set-ItemProperty -Path $RegKeyPath -Name "AppsUseLightTheme" -Value 1
Set-ItemProperty -Path $RegKeyPath -Name "SystemUsesLightTheme" -Value 1
}
Restart-Process -ProcessName explorer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;p&gt;create a shorcut file in a convenient location and name it toggle.exe &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;p&gt;Open your shortcut's file properties.&lt;br&gt;
Add a target for your shortcut like this:&lt;br&gt;
&lt;code&gt;C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "C:\path\to\your\theme\toggle\script.ps1"&lt;/code&gt;&lt;br&gt;
Also add a keyboard shortut you'd like to switch your themes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nPJXKrQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgluww1r81v14gz6ahs4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nPJXKrQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgluww1r81v14gz6ahs4.png" alt="Shortcut file properties" width="709" height="961"&gt;&lt;/a&gt;&lt;br&gt;
Now half of the work is done! Let's test it. Press the keyboard shortcut and your Windows theme will toggle beteween dark/light mode.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;p&gt;Set your apps to follow System theme. Many windows apps supports this options in their settings. For example: vscode allows you to set preffered light and dark themes when you turn on Auto Detect Color Scheme:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Su23VDET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svuzb920g8iyfyb41vpz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Su23VDET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svuzb920g8iyfyb41vpz.png" alt="vscode theme settings" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  As a web developer how do I support this?
&lt;/h2&gt;

&lt;p&gt;CSS has very handy &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"&gt;prefers-color-scheme&lt;/a&gt; media query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (prefers-color-scheme: dark) {
  .theme {
    background: black;
    color: white;
  }
}
@media (prefers-color-scheme: light) {
  .theme {
    background: white;
    color: black;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Angular, you can create service that will expose a signal like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable({
  providedIn: 'root',
})
export class SystemMediaService {
  #query = '(prefers-color-scheme: dark)';
  #prefersColorScheme = signal&amp;lt;'dark' | 'light'&amp;gt;(window.matchMedia(this.#query).matches ? 'dark' : 'light');
  prefersColorScheme = computed(() =&amp;gt; this.#prefersColorScheme());

  constructor() {
    window.matchMedia(this.#query).addEventListener('change', event =&amp;gt; {
      this.#prefersColorScheme.set(event.matches ? 'dark' : 'light');
    });
  }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enjoy your work in the sunlight
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--54lmDjsE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nyygvgcjz5efs2do4vwc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--54lmDjsE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nyygvgcjz5efs2do4vwc.jpg" alt="work in sunlight" width="612" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>theme</category>
      <category>css</category>
    </item>
  </channel>
</rss>
