<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>devtool | Kate Gable</title>
	<atom:link href="https://www.katesky.com/tag/devtool/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.katesky.com</link>
	<description>sharing knowledge, encouraging to learn, promoting passion for coding, supporting mothers who code</description>
	<lastBuildDate>Fri, 26 Jun 2020 18:32:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
<site xmlns="com-wordpress:feed-additions:1">193364748</site>	<item>
		<title>Angular NGRX enabling DevTools at runtime</title>
		<link>https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=angular-ngrx-enabling-devtools-at-runtime</link>
		
		<dc:creator><![CDATA[Katerina Gable]]></dc:creator>
		<pubDate>Mon, 22 Jun 2020 20:51:26 +0000</pubDate>
				<category><![CDATA[angular]]></category>
		<category><![CDATA[devtool]]></category>
		<category><![CDATA[ngrx]]></category>
		<category><![CDATA[redux]]></category>
		<guid isPermaLink="false">https://www.katesky.com/?p=169</guid>

					<description><![CDATA[<p>Angular NGRX enabling DevTools at runtime In this article, I will cover a problem that I was working on in one of my projects. With help from the NGRX team, I was able to solve it.  Shot-out to @brandontroberts , @tim_deschryver, @AlexOkrushko! <br /><a href="https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime/" class="more-link">Read More</a></p>
The post <a href="https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime/">Angular NGRX enabling DevTools at runtime</a> first appeared on <a href="https://www.katesky.com">Kate Gable</a>.]]></description>
										<content:encoded><![CDATA[<body>
<h2 class="wp-block-heading">Angular NGRX enabling DevTools at runtime</h2>



<p>In this article, I will cover a problem that I was working on in one of my projects. With help from the NGRX team, I was able to solve it.  Shot-out to <a href="https://twitter.com/brandontroberts">@brandontroberts</a> , <a href="https://twitter.com/tim_deschryver">@tim_deschryver</a>, <a href="https://twitter.com/AlexOkrushko">@AlexOkrushko</a>!</p>



<p>I hope it helps you when using NGRX, and you can also add it as part of your development process. </p>



<h3 class="wp-block-heading">Problem:</h3>



<p>I wanted to be able to enable DevTools at runtime. The reason I want to do that is to be able to let users report his/her application experience and especially the problems they are experiencing. </p>



<p>In other words, enable debugging reporting on the fly using NGRX framework.</p>



<h3 class="wp-block-heading">Solution:</h3>



<p>This article will be useful if you love Redux DevTools, but you don’t have them enabled in Production.</p>



<p>You would like to have your application to be able to switch to the reporting mode, even in Production.</p>



<p>I will cover the following steps:</p>



<ol class="wp-block-list"><li>Adding a lazy-loaded Feature Module</li><li>Dispatching an effect to create a StoreDevtoolsModule at runtime</li><li>Extras:<ol><li>Use hidden F1 key to enable a link for debugging. </li><li>Enable third party logging/debugging tools  </li></ol></li></ol>



<h3 class="wp-block-heading">Implementation:</h3>



<p>We start by adding a feature; we will call it ‘debug’.  </p>



<p>It will contain:</p>



<ol class="wp-block-list"><li> debug.action – We will use an NGRX action from this file to dispatch from the component.</li><li>debug.component. We will use Debug component to load our feature via a new route we will add to app.module. </li><li>debug.module – We will lazy-load this module that in the app.module, and it will contain a route to the component</li><li>app.module – Register a new feature with a lazy-loaded route</li><li>dev-tools.module – Module that will inject the StoreDevTools to kick-of the Redux tools registration from this module.</li><li>debug.effect – We will use this NGRX effect to catch an action dispatched. This effect will be responsible for the runt-time enabling of the dev tools.</li><li>root-store.module – Register new Effect in RootModule</li><li>app.componet – Add a hiddent button that can be turned visible by F1- hot key</li></ol>



<h4 class="wp-block-heading">debug.action.ts</h4>



<p>Add a new action to be dispatch to the store about the state change. </p>



<p>We prefix the type of the action with the name of the page that will dispatch this action. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [3]; title: ; notranslate">
import { createAction } from '@ngrx/store';

export const enableDebug = createAction('[Debug Page] enable');
</pre></div>


<h4 class="wp-block-heading">debug.component.ts</h4>



<p>Add a new component. If you like, you can keep template and styles inline. Both are not used in this setup, so can easily be excluded. </p>



<p>I have an empty template because its not needed.</p>



<p>When component is loaded it will dispatch an action that will enable DevTools (line 14).  Effect is below, I promise!</p>



<p><strong>in terminal:</strong></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
ng generate component debug--inlineTemplate=true --inlineStyle=true
</pre></div>


<p><strong>in new file debug.component.ts</strong>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [14]; title: ; notranslate">
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { RootState } from '../+state/root.selectors';
import { enableDebug } from './debug.actions';

@Component({
  template: ``,
  selector: 'app-debug'
})
export class DebugComponent implements OnInit {
  constructor(private readonly store: Store&lt;RootState&gt;) {}

  ngOnInit(): void {
    this.store.dispatch(enableDebug());
  }
}

</pre></div>


<h4 class="wp-block-heading">debug.module.ts</h4>



<p>This module is lazy-loaded so it will be registering the child routes.</p>



<p><strong>debug.module.ts</strong>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [6]; title: ; notranslate">
import { NgModule } from '@angular/core';
import { DebugComponent } from './debug.component';
import { RouterModule } from '@angular/router';
@NgModule({
  imports: [ 
      RouterModule.forChild([{ path:'',component:DebugComponent}])
  ],
  declarations: [DebugComponent],
  exports: [DebugComponent]

})
export class DebugModule {
  constructor(){}
}

</pre></div>


<h4 class="wp-block-heading">app.module.ts</h4>



<p>This module we will add a new route and lazy-load it with a feature module. </p>



<p>This is a code-snipet , so if you want to see full code check out my repository.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [4,5,6]; title: ; notranslate">
{
    path: 'debug',
    loadChildren: () =&gt;
    import('./debug/debug.module').then(
      m =&gt; m.DebugModule
    )
      
  },
</pre></div>


<h4 class="wp-block-heading">dev-tools.module.ts</h4>



<p>This module will be compiled and created in the effect. </p>



<p>On line 14th you can refresh the tools. I didn’t see much of a difference in value having it execute.</p>



<p></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [13,16]; title: ; notranslate">
import { NgModule } from '@angular/core';
import { StoreDevtoolsModule, StoreDevtools } from '@ngrx/store-devtools';
@NgModule({
  imports: [
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: true
    })
  ]
})
export class DevToolsModule {
  constructor(private storeDevtools: StoreDevtools) {
    // storeDevtools.refresh();
  }
} 

</pre></div>


<h4 class="wp-block-heading">debug.effect.ts</h4>



<p>Effect class is responsible for reacting to the action dispatched from the component.  It filters out actions that it is subscribing to and when enableDebug is dispatched, effect is using ‘exhaustMat’ operator to make sure that if same action is dispatched it will continue to execute. In other words dropping incoming request.</p>



<p>Next it uses injected compiler object to compile dev-tools.module and creates it on lines 21-24.</p>



<p>Once that is completed, we have devtools enabled and redux tools can be used to track our state changes.</p>



<p>We know that we will have a manual mechanism of turning debugging option on so we can redirect our user back to that location. In this case it’s root of the application or home. So the changeLink action is returned via this effect.</p>



<p></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [21,22,23,24]; title: ; notranslate">
import { Injectable, Compiler, Injector } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';

import * as DebugActions from './debug.actions';
import { exhaustMap } from 'rxjs/operators';
import { DevToolsModule } from './dev-tools-module'; 
import { changeLink } from '../+state/root.actions';

@Injectable()
export class DebugEffects {
  constructor(
    private actions$: Actions,
    private compiler: Compiler,
    private injector: Injector
  ) {}

  debugAction$ = createEffect(() =&gt;
    this.actions$.pipe(
      ofType(DebugActions.enableDebug),
      exhaustMap(async () =&gt; {
        const m = this.compiler.compileModuleSync&lt;DevToolsModule&gt;(
          DevToolsModule
        );
        m.create(this.injector); 
        return changeLink({ link: '' });
      })
    )
  );
}

</pre></div>


<p>If you checkout my repository you will see that I just imported DevToolsModule into the DebugModule for simplicity. I kept the effect for other use case in Extra#2.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [8]; title: ; notranslate">
import { NgModule } from '@angular/core';
import { DebugComponent } from './debug.component';
import { RouterModule } from '@angular/router';
import { DevToolsModule } from './dev-tools-module';
@NgModule({
  imports: [ 
      RouterModule.forChild([{ path:'',component:DebugComponent}]),
      DevToolsModule
  ],
  declarations: [DebugComponent],
  exports: [DebugComponent]

})
export class DebugModule {
  constructor(){}
  
}

</pre></div>


<h4 class="wp-block-heading">app.component.html</h4>



<p>Add anywhere you would like to include a hidden button. So next time your user is having some unexplainable issues they can hit F1 and it will become visible.</p>



<p>Can you tell I am using material components?  So if you this code make sure you import all necessary Modules for Material <a href="https://material.angular.io/components/button/api" target="_blank" rel="noreferrer noopener">here</a>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; title: ; notranslate">
&lt;button *ngIf="isDebugVisible" (click)="onDebug()"mat-icon-button aria-label="debug"&gt;
  &lt;mat-icon&gt;bug_report&lt;/mat-icon&gt;
&lt;/button&gt;
</pre></div>


<h4 class="wp-block-heading">app.component.ts</h4>



<p>Extra #1: As promised I will give this little trick. I added hidden button to help user discover issues and be part of the debugging process.</p>



<p>We will add a function to make our button visible with HostListener, filtering out keys. </p>



<p>Next we will add a button click event that will redirect our user to the lazy-loaded module we just setup.  </p>



<p><strong>Remember</strong>: user will be redirected back here from the debug.effect? </p>



<p>So we can turn off the button – our devtools are enabled!</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; title: ; notranslate">
  onDebug() {
    this.store.dispatch(changeLink({ link: 'debug' }));
    this.isDebugVisible = false;
  }
  @HostListener('document:keydown', ['$event'])
  keypress(e: KeyboardEvent) {
    if (e.key === 'F1') {
      this.isDebugVisible = true;
    }
  }
</pre></div>


<h4 class="wp-block-heading">Extras #2</h4>



<p>If you haven’t heard of LogRocket yet. Let me Introduce you. <a href="http://www.logrocket.com">www.logrocket.com</a> This is a very cool product that you can plugin to the application to see a full path of your user experience with visual snap shots.</p>



<p>How cool is that?</p>



<p>If you follow their instruction it is pretty straight forward to include and get started with in your application.</p>



<p><strong> https://app.logrocket.com/&lt;replace-with-yourcode&gt;/settings/integrations/</strong></p>



<p>It is a paid product, if you exceed the number of requests that are free! </p>



<p>But let see if we can utilize a free version by only enabling the setup from our debug lazy-loaded module dev-tools.module? </p>



<p><strong>update debug.effect.ts</strong></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [7,26]; title: ; notranslate">
import { Injectable, Compiler, Injector } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';

import * as DebugActions from './debug.actions';
import { exhaustMap } from 'rxjs/operators';
import { DevToolsModule, LOGROCKET_INIT_KEY } from './dev-tools-module';
import * as LogRocket from 'logrocket'; 
import { changeLink } from '../+state/root.actions';

@Injectable()
export class DebugEffects {
  constructor(
    private actions$: Actions,
    private compiler: Compiler,
    private injector: Injector
  ) {}

  debugAction$ = createEffect(() =&gt;
    this.actions$.pipe(
      ofType(DebugActions.enableDebug),
      exhaustMap(async () =&gt; {
        const m = this.compiler.compileModuleSync&lt;DevToolsModule&gt;(
          DevToolsModule
        );
        m.create(this.injector);
        LogRocket.init(LOGROCKET_INIT_KEY);
        return changeLink({ link: '' });
      })
    )
  );
}

</pre></div>


<p><strong>update dev-tool.module.ts</strong></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: jscript; highlight: [3,4,5,6,7,8,9,10,11,12,13,14,15,16,24,25,26,27,28,29,30,31]; title: ; notranslate">
import { NgModule } from '@angular/core';
import { StoreDevtoolsModule, StoreDevtools } from '@ngrx/store-devtools';
import { USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
import * as LogRocket from 'logrocket';
import createNgrxMiddleware from 'logrocket-ngrx';
import { MetaReducer, State } from '@ngrx/store'; 
import { RootState } from '../+state/root.selectors';
const logrocketMiddleware = createNgrxMiddleware(LogRocket, {});

export const metaReducers: MetaReducer&lt;any&gt;[] = [];

export function getMetaReducers(): MetaReducer&lt;RootState&gt;[] {
  return metaReducers.concat([logrocketMiddleware]);
}
export const LOGROCKET_INIT_KEY = '&lt;replace-with-your-code';

@NgModule({
  imports: [
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: true
    })
  ],
  providers: [
  
    {
      provide: USER_PROVIDED_META_REDUCERS,
      useFactory: getMetaReducers
    }
  ]}
)
export class DevToolsModule {
  constructor(private storeDevtools: StoreDevtools) {
    // storeDevtools.refresh();
  }
}

</pre></div>


<p>Now that we have this setup, we can see our requests are only feeding into our LogRocket account after we enabled debug!</p>



<p></p>



<p>I hope you enjoyed this article! Tweet you questions or comments <a rel="noreferrer noopener" href="https://twitter.com/intent/tweet?text=Hi,@katesky8%20%22Question/comment%20about%20your%20post%20Angular%20NGRX%20enabling%20DevTools%20at%20runtime%20%F0%9F%91%8D%F0%9F%91%8D%F0%9F%91%8D&amp;url=https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime" target="_blank">here</a>. </p>



<p>I will be glad to connect too!</p>



<p></p>



<ul class="wp-block-social-links is-layout-flex wp-block-social-links-is-layout-flex">



<li class="wp-social-link wp-social-link-twitter  wp-block-social-link"><a href="https://twitter.com/intent/tweet?text=Hi,@katesky8%20Question/comment%20about%20your%20post%20Angular%20NGRX%20enabling%20DevTools%20at%20runtime%20%F0%9F%91%8D%F0%9F%91%8D%F0%9F%91%8D&amp;url=https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime" class="wp-block-social-link-anchor"><svg width="24" height="24" viewbox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M22.23,5.924c-0.736,0.326-1.527,0.547-2.357,0.646c0.847-0.508,1.498-1.312,1.804-2.27 c-0.793,0.47-1.671,0.812-2.606,0.996C18.324,4.498,17.257,4,16.077,4c-2.266,0-4.103,1.837-4.103,4.103 c0,0.322,0.036,0.635,0.106,0.935C8.67,8.867,5.647,7.234,3.623,4.751C3.27,5.357,3.067,6.062,3.067,6.814 c0,1.424,0.724,2.679,1.825,3.415c-0.673-0.021-1.305-0.206-1.859-0.513c0,0.017,0,0.034,0,0.052c0,1.988,1.414,3.647,3.292,4.023 c-0.344,0.094-0.707,0.144-1.081,0.144c-0.264,0-0.521-0.026-0.772-0.074c0.522,1.63,2.038,2.816,3.833,2.85 c-1.404,1.1-3.174,1.756-5.096,1.756c-0.331,0-0.658-0.019-0.979-0.057c1.816,1.164,3.973,1.843,6.29,1.843 c7.547,0,11.675-6.252,11.675-11.675c0-0.178-0.004-0.355-0.012-0.531C20.985,7.47,21.68,6.747,22.23,5.924z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Twitter</span></a></li>







<li class="wp-social-link wp-social-link-twitter  wp-block-social-link"><a href="https://twitter.com/KateSky8" class="wp-block-social-link-anchor"><svg width="24" height="24" viewbox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M22.23,5.924c-0.736,0.326-1.527,0.547-2.357,0.646c0.847-0.508,1.498-1.312,1.804-2.27 c-0.793,0.47-1.671,0.812-2.606,0.996C18.324,4.498,17.257,4,16.077,4c-2.266,0-4.103,1.837-4.103,4.103 c0,0.322,0.036,0.635,0.106,0.935C8.67,8.867,5.647,7.234,3.623,4.751C3.27,5.357,3.067,6.062,3.067,6.814 c0,1.424,0.724,2.679,1.825,3.415c-0.673-0.021-1.305-0.206-1.859-0.513c0,0.017,0,0.034,0,0.052c0,1.988,1.414,3.647,3.292,4.023 c-0.344,0.094-0.707,0.144-1.081,0.144c-0.264,0-0.521-0.026-0.772-0.074c0.522,1.63,2.038,2.816,3.833,2.85 c-1.404,1.1-3.174,1.756-5.096,1.756c-0.331,0-0.658-0.019-0.979-0.057c1.816,1.164,3.973,1.843,6.29,1.843 c7.547,0,11.675-6.252,11.675-11.675c0-0.178-0.004-0.355-0.012-0.531C20.985,7.47,21.68,6.747,22.23,5.924z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Twitter</span></a></li></ul>



<p>If you would like to see a repository where I added this implementation,  follow this github link: </p>



<p><a href="https://github.com/katesky/saraphan-radio/tree/azure/apps/shell-app/src/app/debug">https://github.com/katesky/saraphan-radio/tree/azure/apps/shell-app/src/app/debug</a> </p>
</body>The post <a href="https://www.katesky.com/2020/06/22/angular-ngrx-enabling-devtools-at-runtime/">Angular NGRX enabling DevTools at runtime</a> first appeared on <a href="https://www.katesky.com">Kate Gable</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">169</post-id>	</item>
	</channel>
</rss>
