Angular – Rōnin Consulting https://www.ronin.consulting Expert Engineers Delivering Superior Software Mon, 08 Apr 2024 18:09:00 +0000 en-US hourly 1 https://wordpress.org/?v=7.0 https://www.ronin.consulting/wp-content/uploads/2022/01/cropped-Logo-Red-100x100-1-32x32.png Angular – Rōnin Consulting https://www.ronin.consulting 32 32 Angular: Managing RxJS Observable Subscriptions with UntilDestroy https://www.ronin.consulting/front-end/angular-managing-rxjs-observable-subscriptions-with-untildestroy/ Fri, 13 May 2022 14:39:10 +0000 https://www.ronin.consulting/?p=947  

Unsubscribing from the Subscription: What’s The Big Deal?

Whether you’re listening for events from the Router, listening for changes in a FormControl, or making a request to an API with their HttpClient, if you’ve developed in Angular, you’ve interacted with or subscribed to an RxJS Observable. But do you know why and when you’re responsible for unsubscribing from the Subscription?

Why We Unsubscribe

The goal of unsubscribing is to prevent memory leaks.  When debugging code, memory leaks are subtle and easily missed.  In Angular’s case, it also requires a bit of extra knowledge to know when you’re responsible for the Subscription and when Angular is.

When Angular Handles The Subscription

Angular in some cases is nice enough to handle unsubscribing, for example, if you’re making an API call using their HttpClient:

httpClient.get("/v1/heroes").subscribe((heroes:IHero[])=>{});

If you’re using the async Pipe in your HTML:

<app-heroes-list [heroes]="heroes$ | async"></app-heroes-list>

Angular will handle it. But there are several times you’re responsible for unsubscribing.

When The Developer Handles The Subscription

As a developer, you’re responsible for a Subscription in several cases:

  • Subscribing to events from the Router
  • Subscribing to valueChanges from an AbstractControl (ex. ReactiveForms FormGroup, FormArray, FormControl)
  • RxJS Observables and long-lived Operators (ex. Subjects, timer, interval, etc.)

And in these cases, you’ll see a few approaches that developers use to manage them.

Approach One: Assignment and ngOnDestroy

The most basic approach you can take is to store the Subscription and then unsubscribe from it when a Component’s ngOnDestroy lifecycle method is invoked.

@Component(...)
export class HeroesComponent implements OnInit, OnDestroy {

  private mySubscription: Subscription;

  constructor() { }

  private ngOnInit():void {

    this.mySubscription = interval(1000).subscribe(() => { 
         // Do something here. 
    });

  }

  private ngOnDestroy():void {

   this.mySubscription.unsubscribe();

  }
}

Feels like a lot of work. In classes where multiple subscriptions are being made, you could have more variables to hold them or change your mySubscription:Subscription into an array but that doesn’t make for an elegant approach.

Approach Two: RxJS takeUntil()

The takeUntil operator helps us get a bit further in making a clean break with our Subscription. Passing it in as an operator will allow it to mirror the source Observable until a notifier emits.

Once the notifier emits, the Observable stops mirroring and completes. Let’s update our previous example:

@Component(...)
export class HeroesComponent implements OnInit, OnDestroy {

  private notifier$:Subject<boolean> = new Subject<boolean>();

  constructor() { }

  private ngOnInit():void {

    interval(1000).pipe(takeUntil(this.notifier$)).subscribe(() => { 
         // Do something here. 
    });

  }

  private ngOnDestroy():void {

   this.notifier$.next(true);
   this.notifier$.complete();

  }
}

This approach is a bit cleaner, we avoid tracking any number of subscriptions but still have a bit more code just around the management of the notifier. With the next approach, we can make this even easier.

Approach Three: ngneat/until-destroy(Until Destroy) 

If you haven’t come across this operator yet, you definitely need to check out this repo. It’s called ngneat/until-destroy (GitHub Repo) and it’s going to help us clean up our code. In their latest version (as of this article), they provide a decorator for your Component and an operator. Let’s update our previous example one more time:

@UntilDestroy()
@Component(...)
export class HeroesComponent implements OnInit {
 
  constructor() { }

  private ngOnInit():void {

    interval(1000).pipe(untilDestroyed(this)).subscribe(() => { 
         // Do something here. 
    });

  }
}

Note the placement and order of the @UntilDestroy decorator and the argument we pass into the operator. Now we no longer need any class-level variables or code in the ngOnDestroy to handle our Subscription. That’s it!

UntilDestroy:  Until Next Time

Having worked with Angular and RxJS for years, the ngneat/until-destroy library was a breath of fresh air. It’s definitely my preferred approach to Subscription management and hopefully, you’ll find it useful too! If you do have any other questions about his series of code, stay tuned for more random finds in the Angular world, or if you would like to speak directly to a Ronin, contact us today! Our team has been working in Angular for years, and can answer any questions you may have! 

]]>
Angular: You May Have Missed This https://www.ronin.consulting/front-end/angular-you-may-have-missed-this/ Mon, 04 May 2020 02:05:56 +0000 http://www.ronin.consulting/?p=575 If you’ve built an Angular application before, you’ve probably wondered if there are better ways to accomplish common development tasks. When working, we tend to form habits and continually transfer those habits to new platforms without a second thought. But let’s take a look at some ways to make our development lives easier.

Simplifying Style Paths

Have you ever seen relative path imports in SCSS files associated with your Angular @Component? For example:

@import "../../../theme-variables";

Gets kind of painful with a complex project structure. Even worse when you try to refactor that structure. So what’s the preferred way to import SCSS files? The stylePreprocessorOptions property in your angular.json.

The stylePreprocessorOptions allows you to include additional base paths that Angular will pull in when compiling.

"stylePreprocessorOptions": {
  "includePaths": [
    "src/theme"
  ]
}

So now, when your project compiles, imports are simplified into:

@import "theme-variables";

Angular CLI

More than likely, you’ve had some experience with the Angular CLI if you’ve worked with any Angular project. But if you have only heard about it but don’t leverage it, you might want to consider getting familiar with what it offers.

The Angular CLI is a command-line interface that helps initialize, develop, scaffold, and maintain Angular applications. The CLI is a bit more helpful than some of the IDE plugins you may find out there and became even more powerful as of Angular version 6. Let’s take a look at some of the functionality provided by the CLI.

ng generate

Are you still finding yourself creating Angular application classes by hand? With the CLI, there’s a simplified approach using the below command.

ng g component <name>

//ex: ng g component todo

Some things to remember when running these commands.

  • Each class that the CLI can generate has its own set of flags. For example, running the above will create an @Component called todo.component.ts and will add it to the root @NgModule. So when creating a new @Component with the CLI, be sure to use the –module flag to specify which Feature Module it should be a part of.
  • Generation will create any necessary files. For example, generating an @Component will also create the associated Template, Spec, and SCSS files.
  • Run the command in the directory you’d like for the generation to produce its classes in.

ng add

The ng add <package> utilizes your package manager to install dependencies. Those dependencies can have their own installation script which can update your project with configuration changes and additional dependencies. For example, running npm install <package> will install the dependency, whereas the ng add <package> will install the dependency and configure your angular.json

ng update

Given your package.json, the ng update <package> recommends updates to your application. It will help with dependency versioning, and if one of those dependencies provides an update script using schematics, will even update your code.

Feature Modules

Personally, I continually toil over the best structure when building Angular applications. Should this live here?

To help developers organize their code, they introduced the concept of Feature Modules. This best practice helps logically group code into buckets:

  • Domain
  • Routed
  • Routing
  • Service
  • Widget

Within these groupings, Angular has done a great job of helping guide developers with what should be included in each type of Feature Module. The goal here being a clear separation of concerns for reusable, maintainable, and extensible code.

Build Angular Applications The Easy Way 

There are a lot of little tidbits to pick up along the way when building Angular applications. Though their website is a gold mine of documentation, it doesn’t always provide a short list of things to look at. In the future, I hope to provide more in-depth posts for all you Angular fans. Keep checkin’ back or contact us directly to speak to a Rōnin! 

]]>
Angular Resolvers: How To Master Them https://www.ronin.consulting/front-end/angular-resolvers-and-when-to-use-them/ Wed, 08 Apr 2020 23:37:47 +0000 http://www.ronin.consulting/?p=559 When working with Angular resolvers and Components, you’ve probably come across situations where you load the data a Component needs when it loads. Though there’s nothing wrong with that approach, you may find yourself with a lot of repetitive code depending upon how your APIs are structured.

For example, let’s say Acme Inc. has many multiple locations across the world; which we will call Branches. Your job is to build a SPA for them and in that SPA you have:

  • @Component() SuperAwesomeView
    • Needs a listing of Branches
  • @Component() AnotherSuperAwesomeView
    • Needs a listing of Branches

So naturally you may write some Component code that looks like this:

@Component({
    selector: 'app-super-awesome-view',
    templateUrl: './super-awesome-view.component.html',
    styleUrls: ['./super-awesome-view.scss']
})
export class SuperAwesomeViewComponent implements OnInit {
    branches$: Observable<Branch[]>;

    constructor(private branchService: BranchService) {}

    ngOnInit(): void {
        this.branches$ = this.branchService.getAll();
    }
}

Pretty simplistic right? The problem that we introduce with this approach is really around request management in Components. Let’s say these Components require other fairly generic resource information.

export class SuperAwesomeViewComponent implements OnInit {
    branches$: Observable<Branch[]>;
    users$: Observable<User[]>;
    providers$: Observable<Providers[]>;

    constructor(private branchService: BranchService,
private userService: UserService,
private providerService: ProviderService) {}

    ngOnInit(): void {
        this.branches$ = this.branchService.getAll();
        this.users$ = this.userService.getAll();
        this.providers$ = this.providerService.getAll();
    }
}

Now our Component has grown pretty quickly, we’ve introduced more variables, Injectables, and requests. Though 100% necessary for Components that need this data, there is a better way to manage and share these resource requests. Enter the Resolve Interface in Angular, which its concrete implementations are commonly referred to as Resolvers.

Resolvers

Angular resolvers are effectively an @Injectable that implements the Resolve Interface with the goal of returning some data model.

interface Resolve<T> {
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T
}

Though at first glance, you may think “well I was already returning some data in my Component, how is this better?”, the power of the Resolver really comes into play with how Angular uses it.

A Resolver can be added to any Route that you define in your Routing Module, allowing the requests to process during the Router’s navigation lifecycle before your Component is loaded. Some benefits to this approach:

  • When the Component loads, data is preloaded.
  • Component code is more meaningful and less cluttered.
    • More logic geared towards the Components true purpose.
    • Less management around handling loading indicators etc.
  • Code is centralized and modular.
  • Hooking into the Router provides Resolver related events we can listen for.

So let’s explore this a bit and see how we can implement and apply a Resolver, access its data in a Component, and finally provide an indication to the user during navigation that content is loading.

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { BranchService } from '@app/services';
import { Branch } from '@app/models';

@Injectable({ providedIn: 'root' })
export class BranchResolver implements Resolve<Observable<Branch[]>> {
    constructor(private branchService: BranchService) {}
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Branch[]> {
        return this.branchService.getAll();
    }
}

See, easy! In the above example, we marked the class with @Injectable and made it available to the application through its providedIn config property. From there, we implement the Resolve<T> Interface and type it properly; which for us is Resolve<Observable<Branch[]>>. Then implement the resolve function, handing it a reference to the API call we want to make.

Hooking our Angular Resolvers Up

With our Resolver implemented, we can use it in our application. To do so, we need to apply it to any route that needs it. In your Routes array, find the Route that you’d like to apply it do. Within that Route, in addition to the properties like path and component, add one called resolve. This property will take an Object with a property we define and map to the Resolver.

{
   "path":"awesome",
   "component":"SuperAwesomeViewComponent",
   "resolve":{
      "branches":"BranchResolver"
   }
}

Once again, it’s pretty simple right? We’ve quickly built a Resolver and now applied it to our Route. So how do we access the data in our Component?

angular

Accessing Resolver Data

If we hop back to our SuperAwesomeViewComponent example, we will need to amend it a bit.

 export class SuperAwesomeViewComponent implements OnInit {
    branches$: Observable<Branch[]>;

    constructor(private activatedRoute: ActivatedRoute) {}

    ngOnInit(): void {
       const data:Data = this.activatedRoute.snapshot.data;
       this.branches$.next(data.branches);   
    }
}

We’ve swapped out the BranchService for the Angular ActivatedRoute. The ActivatedRoute allows us to access all resolved data and use it in our Component. If you remember that in the Route we added our Resolver to we defined an Object with the data we want to use, the Data object we receive from the ActivatedRoute is that Object.

Router Events and Loading Screen

With data being loaded during the navigation lifecycle and being handed to our Component, we now want to show some indication to the user that we’re loading data. To do this properly, we’ve going to move a bit higher up in the Component tree to the AppComponent. In your SPA, you probably have a root Component like the AppComponent that houses the root router-outlet. This Component will be where we centralize listening for Resolver-based events in the Router and overlaying a loading screen. For example:

export class AppComponent implements OnInit {
  loading: boolean = false;
  constructor(private router: Router) {}

  ngOnInit(): void {
    this.router.events
      .pipe(
        filter(
          event => event instanceof ResolveStart || event instanceof ResolveEnd
        )
      )
      .subscribe((event: RouterEvent) => {
        if (event instanceof ResolveStart) {
          this.loading = true;
        } else if (event instanceof ResolveEnd) {
          this.loading = false;
        }
      });
  }
}

The Router emits two events aimed at the Resolvers, ResolveStart and ResolveEnd. They are pretty straightforward and tell us everything we need to know to show the loading screen. When we receive those events, we toggle a boolean flag to show a loading screen so the user is aware that we are fetching necessary data.

General Thoughts on Resolvers

The above walkthrough is pretty simple and really geared towards an understanding of how they can be used. It’s truly just another useful tool at your disposal when building an Angular application but it isn’t a blanket solution to all scenarios. Below are some thoughts I continually think about while building Angular applications and trying to structure requests properly.

How much can a Resolver Handle?

Resolvers are a great way to preload data, but they really depend on how your APIs are structured and what you expect in return. Are you calling a single API that’s returning a lightweight or heavy model? Or are you calling multiple APIs and performing transformations on the returned data? Regardless of which approach, what’s the user’s experience while it’s resolving? All of these questions are answered on a per project basis but should always be considered.

Error handling in a Resolver?

If we’re requesting data while navigating, you need to be smart about how you handle situations where an API is unreachable or there’s an exception in your API. Connectivity issues are common, whether they be directly to the API or to another service or database that API may use. Is it better to handle the user experience for this in the Component with the ability to reload or is a blanket error page good enough?

What kind of data should be retrieved?

Sure, simple resource data is a good candidate. It’s even better if that resource data tends to be static and can be cached with little overhead towards when to invalidate that cache. But what about things like tabular data?

Is a Resolver a good way to preload the first page of a table so when the Component loads it’s readily available? It could be. Depends on how generic you can make that code and if that code is truly needed in multiple places.

What about form data? I think Resolvers are an excellent way to pulling in data like saved forms and pre-populating those fields. Could it get hairy? Yeah, probably if your pages has a nasty form (which I’ve seen plenty), but it really comes down to how that form data is stored. Is it a single model or composed from different calls?

Conclusion

Resolvers are a super handy feature in Angular. They are simply built, reusable, and makes testing your code a bit simpler. Lastly, I’m honestly not sure most Angular developers are aware that this feature exists, so try implementing one on your project and it could make you look like an Angular guru! If you do, let me know how things went and if you have another angle to consider!

 

To learn more about Angular route Resolvers or more coding questions, contact our team at Rōnin today! 

About Rōnin Consulting – Rōnin Consulting provides software engineering and systems integration services for healthcare, financial services, distribution, technology, and other business lines. Services include custom software development and architecture, cloud and hybrid implementations, business analysis, data analysis, and project management for a range of clients from the Fortune 500 to rapidly evolving startups. For more information, please contact us today.

]]>
What’s in your Angular Bundle? https://www.ronin.consulting/front-end/whats-in-your-angular-bundle/ Wed, 04 Mar 2020 00:56:00 +0000 http://www.ronin.consulting/?p=512

If you’ve ever built an Angular Application before, keeping your build lean and quick is key. With a labyrinth of configuration options and an endless sea of third-party libraries to use, it’s very easy to increase the time it takes to build your application if left unchecked.  Even more so if you work on a large team where developers work in parallel.  So how can we avoid this potential pitfall so your build remains performant?  Below, we will discuss on a particular tool we use to simplify our process: the web pack Angular bundle analyzer tool. 

How to Use the Angular Bundle Tool 

Consider using the web pack Angular bundle analyzer tool to simplify your process.  This tool takes in a stats file generated from the Angular CLI and provides an interactive FoamTree.  The benefit here is quickly identifying problem areas where unnecessary files may be included in your application’s distribution.  Let’s take a look at how to do this. 

Step 1

First, we must install the webpack-bundle-analyzer package and save it to our package.json.  We can do this with the below command.

npm install webpack-bundle-analyze --save-dev

Step 2

Now that the analyzer tool is installed, we need to generate a build of our application with the stats file.  Run the below to generate a production build with the stats file.

ng build --prod --stats-json
BundleAnalyzerOutput
Example Output

Step 3

With the generated build, you can check your dist folder and see the generated stats.json file that was created.  That’s the file we will hand to theangular bundle analyzer to visualize for us.

npx webpack-bundle-analyzer dist/stats.json
BundleAnalyzerFoamTree

This will boot up a local server on port 8888 with our FoamTree.  When you hit the site it may feel a bit overwhelming with how many files are included in your bundle, but you’ll certainly find some weasels in there that could give your application a little boost.

 

It’s that easy, folks! More Angular tips and tricks to come; stay tuned or reach out to a Rōnin for any and all questions!

About Rōnin Consulting – Rōnin Consulting provides software engineering and systems integration services for healthcare, financial services, distribution, technology, and other business lines. Services include custom software development and architecture, cloud and hybrid implementations, business analysis, data analysis, and project management for a range of clients from the Fortune 500 to rapidly evolving startups. For more information, please contact us today.

]]>
Easy Server-Side Processing: Telerik Kendo Grid + Linq + IQueryable + NHibernate https://www.ronin.consulting/microsoft/net-core/easy-server-side-processing-telerik-kendo-grid-linq-iqueryable-nhibernate/ Wed, 26 Feb 2020 00:44:00 +0000 http://www.ronin.consulting/?p=509

Son, pick the right tool for the problem and be a master of your work.

-Walter McClain

My dad’s wise words ring loud as I age, even when developing software.  At Rōnin, we believe using a mature framework or component library is preferable to doing it ourselves.  We go on many journeys of Digital Transformation with companies where one of our specialties is identifying existing line-of-business applications that are candidates for a complete born-in-the-cloud rewrite, allowing us to leverage all the power, features, and functions of Azure.

During these travels, we notice common development patterns.  We perfect them.  We teach our Rōnins and customers.  One interesting pattern that has become one of our favorites is using Kendo Grid for Angular with NHibernate Linq provider and IQueryable.

Problems With Rewriting We Often Run Into

One common problem we encounter when rewriting line-of-business applications for clients is displaying tabular data to the end user.  Our clients are large.  Most have been in existence for over 20+ years.  They are in healthcare, where regulations require them to retain data for long durations.  This translates to data stores containing many, many millions of records.

The issue arises not in the data but in the development approach.  Developers are lazy, and when developing UI/UX that displays data, they read it all into memory and allow a component to handle sorting, filtering, and paging on the client side.  While this is fine for small datasets, performance issues occur for the user when you have record counts of over 1000.

Solution & Easy Server Side Processing

If you get this far, I assume you understand what Kendo Grid, IQueryable, and NHibernate are.  Many articles and blog posts have been made about them containing deep detail, and you can just Google them.

As I mentioned above, we like mature frameworks and component libraries. Kendo, and specifically Kendo Grid for Angular, is one of our favorites to use.

On the server side, in your .NET Core API project, just grab the Telerik NuGet Kendo.DynamicLinqCore when developing your controller.  This contains the IQueryable extensions that make doing server-side processing amazingly simple and elegant.

PS> Install-Package Kendo.DynamicLinqCore

Example – Web API Controller

using Kendo.DynamicLinqCore;

[HttpPost]
public IActionResult Contacts([FromBody] DataSourceRequest requestModel)
{
        return _dbSession.Query<Contact>()                  
               .Select(c => new ContactViewModel // Not required but this shows how to do projection into a view model
               {
                   ContactId = c.ContactId,
                   CompanyName = c.CompanyName,
                   ContactName = c.ContactName,
                   City = c.City,
                   ContactTitle = c.ContactTitle
               })
               .ToDataSourceResult(requestModel.Take, requestModel.Skip, requestModel.Sort, requestModel.Filter, requestModel.Aggregate, requestModel.Group);
}

At first glance, you may wonder, would this not first read all the data from the database and then do the filtering, sorting, paging, etc. in memory?  Yeah, that’s what I thought, too, but it doesn’t, and I have done SQL tracing to see it in action.  The library is using Dynamic Linq to create Linq queries based on the request that it is given.  NHibernate’s Linq provider then translates this into a proper SQL query.

Example – Angular/TypeScript

On the client-side in your Angular Component, implement the onStateChang(state: State) method and then in the Kendo Grid Component in your HTML template, set this method as the dataStateChange event handler.

Then in your method you get handed the new grid state representing the client-side version of the DataSourceRequest object.  Now you will take this and pass it to the service that will then POST it up to your API controller.

public onStateChange(state: State) {
	this.gridState = state;

	this.contactService.load(state);
}

And your service load code will look something similar to the following.
load(newGridState?: State): Observable<GridDataResult> {
    return this.http.post<GridDataResult>(`${this.baseUrl}/search`, newGridState).pipe(
      catchError(this.handleError('load contacts failed’, null))
    );
  }

Finally, this approach works great for about 75-80% of the needs for displaying large amounts of data.  It will break down when you have very complex search needs across complicated data models.  In those cases, you can still use the DataSourceRequest to get all the grid state information you need.  With that information, you can then construct your own NHibernate QueryOver queries.

Again, like Dad says… pick the right tool for the right problem.

Cheers!

About Rōnin Consulting – Rōnin Consulting provides software engineering and systems integration services for healthcare, financial services, distribution, technology, and other business lines. Services include custom software development and architecture, cloud and hybrid implementations, business analysis, data analysis, and project management for a range of clients from the Fortune 500 to rapidly evolving startups. For more information, please contact us today.

]]>